Merge branch 'bw/autoconf'
authorJunio C Hamano <gitster@pobox.com>
Fri, 20 Mar 2009 21:30:08 +0000 (14:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 20 Mar 2009 21:30:08 +0000 (14:30 -0700)
* bw/autoconf:
configure: rework pthread handling to allow for user defined flags
configure: make iconv tests aware of user arguments
configure: asciidoc version test cleanup
configure: wrap some library tests with GIT_STASH_FLAGS
configure: add macros to stash FLAG variables
configure: reorganize flow of argument checks
configure: ensure settings from user are also usable in the script

145 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes-1.6.2.1.txt
Documentation/RelNotes-1.6.3.txt
Documentation/config.txt
Documentation/git-branch.txt
Documentation/git-checkout.txt
Documentation/git-config.txt
Documentation/git-filter-branch.txt
Documentation/git-grep.txt
Documentation/git-merge.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-remote.txt
Documentation/git-rev-parse.txt
Documentation/git-send-email.txt
Documentation/git.txt
Documentation/gitcli.txt
Documentation/glossary-content.txt
Documentation/user-manual.txt
Makefile
branch.c
branch.h
builtin-add.c
builtin-apply.c
builtin-archive.c
builtin-clone.c
builtin-config.c
builtin-diff-tree.c
builtin-fetch-pack.c
builtin-fetch.c
builtin-for-each-ref.c
builtin-gc.c
builtin-grep.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-push.c
builtin-remote.c
builtin-send-pack.c
builtin-shortlog.c
builtin-update-index.c
cache.h
combine-diff.c
compat/mingw.c
compat/mingw.h
compat/win32mmap.c [new file with mode: 0644]
compat/winansi.c
config.c
connect.c
contrib/completion/git-completion.bash
contrib/difftool/git-difftool
contrib/difftool/git-difftool-helper
contrib/difftool/git-difftool.txt
contrib/fast-import/import-tars.perl
diff-lib.c
diffcore-pickaxe.c
dir.c
entry.c
git-compat-util.h
git-rebase--interactive.sh
git-rebase.sh
git-send-email.perl
grep.c
grep.h
http-push.c
imap-send.c
index-pack.c
merge-recursive.c
pretty.c
read-cache.c
refs.c
remote.c
remote.h
sideband.c
sideband.h
strbuf.c
string-list.c
string-list.h
symlinks.c
t/lib-git-svn.sh
t/lib-httpd.sh
t/t0000-basic.sh
t/t0024-crlf-archive.sh
t/t0050-filesystem.sh
t/t1008-read-tree-overlay.sh [new file with mode: 0755]
t/t1100-commit-tree-options.sh
t/t1300-repo-config.sh
t/t1400-update-ref.sh
t/t1410-reflog.sh
t/t2200-add-update.sh
t/t3000-ls-files-others.sh
t/t3010-ls-files-killed-modified.sh
t/t3400-rebase.sh
t/t3404-rebase-interactive.sh
t/t3409-rebase-hook.sh [deleted file]
t/t3413-rebase-hook.sh [new file with mode: 0755]
t/t3600-rm.sh
t/t4006-diff-mode.sh
t/t4013-diff-various.sh
t/t4014-format-patch.sh
t/t4017-quiet.sh [deleted file]
t/t4021-format-patch-signer-mime.sh [deleted file]
t/t4035-diff-quiet.sh [new file with mode: 0755]
t/t4036-format-patch-signer-mime.sh [new file with mode: 0755]
t/t4203-patch-id.sh [deleted file]
t/t4204-patch-id.sh [new file with mode: 0755]
t/t5000-tar-tree.sh
t/t5300-pack-object.sh
t/t5302-pack-index.sh
t/t5303-pack-corruption-resilience.sh
t/t5403-post-checkout-hook.sh
t/t5505-remote.sh
t/t5510-fetch.sh
t/t5511-refspec.sh
t/t5515-fetch-merge-logic.sh
t/t5521-pull-symlink.sh [deleted file]
t/t5522-pull-symlink.sh [new file with mode: 0755]
t/t5540-http-push.sh
t/t5550-http-fetch.sh [new file with mode: 0755]
t/t5601-clone.sh
t/t5602-clone-remote-exec.sh
t/t6023-merge-rename-nocruft.sh [deleted file]
t/t6031-merge-recursive.sh
t/t6034-merge-rename-nocruft.sh [new file with mode: 0755]
t/t7004-tag.sh
t/t7005-editor.sh
t/t7300-clean.sh
t/t7502-status.sh [deleted file]
t/t7508-status.sh [new file with mode: 0755]
t/t9001-send-email.sh
t/t9106-git-svn-dcommit-clobber-series.sh [deleted file]
t/t9108-git-svn-multi-glob.sh [deleted file]
t/t9109-git-svn-multi-glob.sh [new file with mode: 0755]
t/t9137-git-svn-dcommit-clobber-series.sh [new file with mode: 0755]
t/t9200-git-cvsexportcommit.sh
t/t9400-git-cvsserver-server.sh
t/t9401-git-cvsserver-crlf.sh
t/t9500-gitweb-standalone-no-errors.sh
t/t9700-perl-git.sh
t/test-lib.sh
transport.c
unpack-trees.c
xdiff/xdiffi.c
xdiff/xemit.c
index 0d7fa9cca9e5c3ec8a11cd2c878f5a7afe353abe..b8bf618a30fd32a014e41e1ba9914f5e652bdefd 100644 (file)
@@ -129,3 +129,6 @@ For C programs:
    used in the git core command set (unless your command is clearly
    separate from it, such as an importer to convert random-scm-X
    repositories to git).
+
+ - When we pass <string, length> pair to functions, we should try to
+   pass them in that order.
index a33782d47cfcca1ccd30116af9996960f2634513..dfa36416af24417b120b2ddf449bde40716e025f 100644 (file)
@@ -17,9 +17,3 @@ Fixes since v1.6.2
   correct .git directory.
 
 * git-send-email learned to correctly handle multiple Cc: addresses.
-
----
-exec >/var/tmp/1
-O=v1.6.2-21-g7681ed2
-echo O=$(git describe maint)
-git shortlog --no-merges $O..maint
index 7f36b6c5c1d66dcb195370c0787b31944d1a1965..4353cbf8c32cf7384c8fffebbb63e8ca9764ada9 100644 (file)
@@ -30,8 +30,18 @@ Updates since v1.6.2
 
 (performance)
 
+* many uses of lstat(2) in the codepath for "git checkout" have been
+  optimized out.
+
 (usability, bells and whistles)
 
+* rsync:/path/to/repo can be used to run git over rsync for local
+  repositories.  It may not be useful in practice; meant primarily for
+  testing.
+
+* (msysgit) progress output that is sent over the sideband protocol can
+  be handled appropriately in Windows console.
+
 * "--pretty=<style>" option to the log family of commands can now be
   spelled as "--format=<style>".  In addition, --format=%formatstring
   is a short-hand for --pretty=tformat:%formatstring.
@@ -47,15 +57,23 @@ Updates since v1.6.2
 * git-bisect shows not just the number of remaining commits whose goodness
   is unknown, but also shows the estimated number of remaining rounds.
 
+* You can give --date=<format> option to git-blame.
+
 * git-branch -r shows HEAD symref that points at a remote branch in
   interest of each tracked remote repository.
 
 * git-config learned -e option to open an editor to edit the config file
   directly.
 
+* git-clone runs post-checkout hook when run without --no-checkout.
+
 * git-format-patch can be told to use attachment with a new configuration,
   format.attach.
 
+* git-format-patch can be told to produce deep or shallow message threads.
+
+* git-grep learned to highlight the found substrings in color.
+
 * git-imap-send learned to work around Thunderbird's inability to easily
   disable format=flowed with a new configuration, imap.preformattedHTML.
 
@@ -63,6 +81,10 @@ Updates since v1.6.2
   descendant of the commit you are rebasing onto with --force-rebase
   option.
 
+* git-rebase can be told to report diffstat with the --stat option.
+
+* Output from git-remote command has been vastly improved.
+
 * git-send-email learned --confirm option to review the Cc: list before
   sending the messages out.
 
@@ -70,6 +92,8 @@ Updates since v1.6.2
 
 * Test scripts can be run under valgrind.
 
+* Makefile learned 'coverage' option to run the test suites with
+  coverage tracking enabled.
 
 Fixes since v1.6.2
 ------------------
@@ -80,8 +104,30 @@ release, unless otherwise noted.
 Here are fixes that this release has, but have not been backported to
 v1.6.2.X series.
 
+* "git diff --pickaxe-regexp" did not count overlapping matches
+  correctly (backport by cherry-picking 50fd699).
+
+* "git-fetch" in a repository that was not cloned from anywhere said
+  it cannot find 'origin', which was hard to understand for new people.
+
+* git-gc spent excessive amount of time to decide if an object appears
+  in a locally existing pack (if needed, backport by merging 69e020a).
+
+* "git-ls-files --deleted" did not work well with GIT_DIR&GIT_WORK_TREE
+  (backport by cherry-picking 8ad3dae).
+
+* "git-read-tree A B C..." without -m option has been broken for a long time
+  (backport by merging jc/maint-1.6.0-read-tree-overlay)
+
+* 'git-submodule add' did not tolerate extra slashes and ./ in the
+  path it accepted from the command line; it now is more lenient
+ (if needed, backport by merging db75ada).
+
+* git-send-email ignored --in-reply-to when --no-thread was given
+  (backport by merging tr/maint-1.6.0-send-email-irt)
+
 ---
 exec >/var/tmp/1
-O=v1.6.2-77-g8cc3fe4
+O=v1.6.2.1-213-g7d4e3a7
 echo O=$(git describe master)
 git shortlog --no-merges $O..master ^maint
index 56bd781a163d70ce23f1b6932ce3b1c70510d3b5..12540b605f4f15e93703bed226ab43c0b8d6716b 100644 (file)
@@ -25,7 +25,7 @@ blank lines are ignored.
 The file consists of sections and variables.  A section begins with
 the name of the section in square brackets and continues until the next
 section begins.  Section names are not case sensitive.  Only alphanumeric
-characters, '`-`' and '`.`' are allowed in section names.  Each variable
+characters, `-` and `.` are allowed in section names.  Each variable
 must belong to some section, which means that there must be section
 header before first setting of a variable.
 
@@ -39,7 +39,7 @@ in the section header, like in example below:
 --------
 
 Subsection names can contain any characters except newline (doublequote
-'`"`' and backslash have to be escaped as '`\"`' and '`\\`',
+`"` and backslash have to be escaped as `\"` and `\\`,
 respectively) and are case sensitive.  Section header cannot span multiple
 lines.  Variables may belong directly to a section or to a given subsection.
 You can have `[section]` if you have `[section "subsection"]`, but you
@@ -53,7 +53,7 @@ All the other lines are recognized as setting variables, in the form
 'name = value'.  If there is no equal sign on the line, the entire line
 is taken as 'name' and the variable is recognized as boolean "true".
 The variable names are case-insensitive and only alphanumeric
-characters and '`-`' are allowed.  There can be more than one value
+characters and `-` are allowed.  There can be more than one value
 for a given variable; we say then that variable is multivalued.
 
 Leading and trailing whitespace in a variable value is discarded.
@@ -69,15 +69,15 @@ String values may be entirely or partially enclosed in double quotes.
 You need to enclose variable value in double quotes if you want to
 preserve leading or trailing whitespace, or if variable value contains
 beginning of comment characters (if it contains '#' or ';').
-Double quote '`"`' and backslash '`\`' characters in variable value must
-be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'.
+Double quote `"` and backslash `\` characters in variable value must
+be escaped: use `\"` for `"` and `\\` for `\`.
 
-The following escape sequences (beside '`\"`' and '`\\`') are recognized:
-'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB)
-and '`\b`' for backspace (BS).  No other char escape sequence, nor octal
+The following escape sequences (beside `\"` and `\\`) are recognized:
+`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
+and `\b` for backspace (BS).  No other char escape sequence, nor octal
 char sequences are valid.
 
-Variable value ending in a '`\`' is continued on the next line in the
+Variable value ending in a `\` is continued on the next line in the
 customary UNIX fashion.
 
 Some variables may require special value format.
@@ -221,6 +221,11 @@ core.gitProxy::
 Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
 (which always applies universally, without the special "for"
 handling).
++
+The special string `none` can be used as the proxy command to
+specify that no proxy be used for a given domain pattern.
+This is useful for excluding servers inside a firewall from
+proxy use, while defaulting to a common proxy for external domains.
 
 core.ignoreStat::
        If true, commands which modify both the working tree and the index
@@ -382,9 +387,9 @@ core.pager::
        to override git's default settings this way, you need
        to be explicit.  For example, to disable the S option
        in a backward compatible manner, set `core.pager`
-       to "`less -+$LESS -FRX`".  This will be passed to the
+       to `less -+$LESS -FRX`.  This will be passed to the
        shell by git, which will translate the final command to
-       "`LESS=FRSX less -+FRSX -FRX`".
+       `LESS=FRSX less -+FRSX -FRX`.
 
 core.whitespace::
        A comma separated list of common whitespace problems to
@@ -548,6 +553,25 @@ color.diff.<slot>::
        whitespace errors). The values of these variables may be specified as
        in color.branch.<slot>.
 
+color.grep::
+       When set to `always`, always highlight matches.  When `false` (or
+       `never`), never.  When set to `true` or `auto`, use color only
+       when the output is written to the terminal.  Defaults to `false`.
+
+color.grep.external::
+       The string value of this variable is passed to an external 'grep'
+       command as a command line option if match highlighting is turned
+       on.  If set to an empty string, no option is passed at all,
+       turning off coloring for external 'grep' calls; this is the default.
+       For GNU grep, set it to `--color=always` to highlight matches even
+       when a pager is used.
+
+color.grep.match::
+       Use customized color for matches.  The value of this variable
+       may be specified as in color.branch.<slot>.  It is passed using
+       the environment variables 'GREP_COLOR' and 'GREP_COLORS' when
+       calling an external 'grep'.
+
 color.interactive::
        When set to `always`, always use colors for interactive prompts
        and displays (such as those used by "git-add --interactive").
@@ -1161,7 +1185,7 @@ pager.<cmd>::
        particular git subcommand when writing to a tty.  If
        `\--paginate` or `\--no-pager` is specified on the command line,
        it takes precedence over this option.  To disable pagination for
-       all commands, set `core.pager` or 'GIT_PAGER' to "`cat`".
+       all commands, set `core.pager` or `GIT_PAGER` to `cat`.
 
 pull.octopus::
        The default merge strategy to use when pulling multiple branches
index 6103d62fe3dca23c78b16dbdbb5ba231a6b39bf7..27b73bcf9e0a140eceb32343592d9b2415918e90 100644 (file)
@@ -76,8 +76,8 @@ OPTIONS
        based sha1 expressions such as "<branchname>@\{yesterday}".
 
 -f::
-       Force the creation of a new branch even if it means deleting
-       a branch that already exists with the same name.
+       Reset <branchname> to <startpoint> if <branchname> exists
+       already. Without `-f` 'git-branch' refuses to change an existing branch.
 
 -m::
        Move/rename a branch and the corresponding reflog.
index 125d8f3c32470cd0917bade45ed7e9fcd7f4c376..1a6c19e5c39ad038e3fa073926683a21d7c21935 100644 (file)
@@ -133,9 +133,9 @@ the conflicted merge in the specified paths.
 When this parameter names a non-branch (but still a valid commit object),
 your HEAD becomes 'detached'.
 +
-As a special case, the "`@\{-N\}`" syntax for the N-th last branch
+As a special case, the `"@\{-N\}"` syntax for the N-th last branch
 checks out the branch (instead of detaching).  You may also specify
-"`-`" which is synonymous with "`@\{-1\}`".
+`-` which is synonymous with `"@\{-1\}"`.
 
 
 Detached HEAD
index 82ce89eae849e5a1c697a3c7f659a80521600348..7131ee3c66951de5981a82e304f4619de88064c5 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]]
 'git config' [<file-option>] [type] --add name value
-'git config' [<file-option>] [type] --replace-all name [value [value_regex]]
+'git config' [<file-option>] [type] --replace-all name value [value_regex]
 'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
 'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
 'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
index 7ffe03f4279a8ca8110806260f33a58f849351e4..237f85e7673e90b214550e051d92c4cb0865413a 100644 (file)
@@ -91,7 +91,9 @@ OPTIONS
 --index-filter <command>::
        This is the filter for rewriting the index.  It is similar to the
        tree filter but does not check out the tree, which makes it much
-       faster.  For hairy cases, see linkgit:git-update-index[1].
+       faster.  Frequently used with `git rm \--cached
+       \--ignore-unmatch ...`, see EXAMPLES below.  For hairy
+       cases, see linkgit:git-update-index[1].
 
 --parent-filter <command>::
        This is the filter for rewriting the commit's parent list.
@@ -204,19 +206,18 @@ However, if the file is absent from the tree of some commit,
 a simple `rm filename` will fail for that tree and commit.
 Thus you may instead want to use `rm -f filename` as the script.
 
-A significantly faster version:
+Using `\--index-filter` with 'git-rm' yields a significantly faster
+version.  Like with using `rm filename`, `git rm --cached filename`
+will fail if the file is absent from the tree of a commit.  If you
+want to "completely forget" a file, it does not matter when it entered
+history, so we also add `\--ignore-unmatch`:
 
 --------------------------------------------------------------------------
-git filter-branch --index-filter 'git rm --cached filename' HEAD
+git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
 --------------------------------------------------------------------------
 
 Now, you will get the rewritten history saved in HEAD.
 
-As with using `rm filename`, `git rm --cached filename` will fail
-if the file is absent from the tree of a commit.  If it is not important
-whether the file is already absent from the tree, you can use
-`git rm --cached --ignore-unmatch filename` instead.
-
 To rewrite the repository to look as if `foodir/` had been its project
 root, and discard all other history:
 
index 553da6cbb1777a94cb3d6b48dc77c445e18ca2b0..fccb82deb48ec75d25f948e7caa69a44e09f5832 100644 (file)
@@ -17,6 +17,7 @@ SYNOPSIS
           [-l | --files-with-matches] [-L | --files-without-match]
           [-z | --null]
           [-c | --count] [--all-match]
+          [--color | --no-color]
           [-A <post-context>] [-B <pre-context>] [-C <context>]
           [-f <file>] [-e] <pattern>
           [--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
@@ -105,6 +106,13 @@ OPTIONS
        Instead of showing every matched line, show the number of
        lines that match.
 
+--color::
+       Show colored matches.
+
+--no-color::
+       Turn off match highlighting, even when the configuration file
+       gives the default to color output.
+
 -[ABC] <context>::
        Show `context` trailing (`A` -- after), or leading (`B`
        -- before), or both (`C` -- context) lines, and place a
index f7be5846a67de1a3215bad3d7b9c263705cd1bba..cc0d30fe7e6c96d25304181ef2fdd9cbd02e7817 100644 (file)
@@ -146,7 +146,7 @@ And here is another line that is cleanly resolved or unmodified.
 ------------
 
 The area where a pair of conflicting changes happened is marked with markers
-"`<<<<<<<`", "`=======`", and "`>>>>>>>`".  The part before the "`=======`"
+`<<<<<<<`, `=======`, and `>>>>>>>`.  The part before the `=======`
 is typically your side, and the part afterwards is typically their side.
 
 The default format does not show what the original said in the conflicting
@@ -173,8 +173,8 @@ Git makes conflict resolution easy.
 And here is another line that is cleanly resolved or unmodified.
 ------------
 
-In addition to the "`<<<<<<<`", "`=======`", and "`>>>>>>>`" markers, it uses
-another "`|||||||`" marker that is followed by the original text.  You can
+In addition to the `<<<<<<<`, `=======`, and `>>>>>>>` markers, it uses
+another `|||||||` marker that is followed by the original text.  You can
 tell that the original just stated a fact, and your side simply gave in to
 that statement and gave up, while the other side tried to have a more
 positive attitude.  You can sometimes come up with a better resolution by
index 4e7e5a719a4b0447159213466d46aa2360b7408e..fd53c49fb886b196ba79e40c4c9c4efe0dae5432 100644 (file)
@@ -24,8 +24,8 @@ every time you push into it, by setting up 'hooks' there.  See
 documentation for linkgit:git-receive-pack[1].
 
 
-OPTIONS
--------
+OPTIONS[[OPTIONS]]
+------------------
 <repository>::
        The "remote" repository that is destination of a push
        operation.  This parameter can be either a URL
@@ -187,6 +187,28 @@ reason::
 Examples
 --------
 
+git push::
+       Works like `git push <remote>`, where <remote> is the
+       current branch's remote (or `origin`, if no remote is
+       configured for the current branch).
+
+git push origin::
+       Without additional configuration, works like
+       `git push origin :`.
++
+The default behavior of this command when no <refspec> is given can be
+configured by setting the `push` option of the remote.
++
+For example, to default to pushing only the current branch to `origin`
+use `git config remote.origin.push HEAD`.  Any valid <refspec> (like
+the ones in the examples below) can be configured as the default for
+`git push origin`.
+
+git push origin :::
+       Push "matching" branches to `origin`. See
+       <refspec> in the <<OPTIONS,OPTIONS>> section above for a
+       description of "matching" branches.
+
 git push origin master::
        Find a ref that matches `master` in the source repository
        (most likely, it would find `refs/heads/master`), and update
index 57bd333f0b3660b12382365ee2b6d8e6c2418f02..3d5a066c31675e502eb027dde824d1966c9c0f09 100644 (file)
@@ -258,11 +258,23 @@ OPTIONS
        context exist they all must match.  By default no context is
        ever ignored.
 
+-f::
+--force-rebase::
+       Force the rebase even if the current branch is a descendant
+       of the commit you are rebasing onto.  Normally the command will
+       exit with the message "Current branch is up to date" in such a
+       situation.
+
 --whitespace=<option>::
        This flag is passed to the 'git-apply' program
        (see linkgit:git-apply[1]) that applies the patch.
        Incompatible with the --interactive option.
 
+--committer-date-is-author-date::
+--ignore-date::
+       These flags are passed to 'git-am' to easily change the dates
+       of the rebased commits (see linkgit:git-am[1]).
+
 -i::
 --interactive::
        Make a list of the commits which are about to be rebased.  Let the
index fad983e297514da7e847196b0375e3254fdf235d..c9c0e6f932909c53bc7041f540e7965f5da4efc7 100644 (file)
@@ -13,6 +13,7 @@ SYNOPSIS
 'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
 'git remote rename' <old> <new>
 'git remote rm' <name>
+'git remote set-head' <name> [-a | -d | <branch>]
 'git remote show' [-n] <name>
 'git remote prune' [-n | --dry-run] <name>
 'git remote update' [group]
@@ -53,8 +54,7 @@ is created.  You can give more than one `-t <branch>` to track
 multiple branches without grabbing all branches.
 +
 With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
-up to point at remote's `<master>` branch instead of whatever
-branch the `HEAD` at the remote repository actually points at.
+up to point at remote's `<master>` branch. See also the set-head command.
 +
 In mirror mode, enabled with `\--mirror`, the refs will not be stored
 in the 'refs/remotes/' namespace, but in 'refs/heads/'.  This option
@@ -76,6 +76,30 @@ the configuration file format.
 Remove the remote named <name>. All remote tracking branches and
 configuration settings for the remote are removed.
 
+'set-head'::
+
+Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for
+the named remote. Having a default branch for a remote is not required,
+but allows the name of the remote to be specified in lieu of a specific
+branch. For example, if the default branch for `origin` is set to
+`master`, then `origin` may be specified wherever you would normally
+specify `origin/master`.
++
+With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted.
++
+With `-a`, the remote is queried to determine its `HEAD`, then
+`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
+`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
+`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
+only work if `refs/remotes/origin/next` already exists; if not it must be
+fetched first.
++
+Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., "git
+remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
+`refs/remotes/origin/master`. This will only work if
+`refs/remotes/origin/master` already exists; if not it must be fetched first.
++
+
 'show'::
 
 Gives some information about the remote <name>.
index 3ccef2f2b3295c6d5e14b8f3a9d354d7b57598da..5ed2bc840f962cfe3af6bf4540edf46f47b9e148 100644 (file)
@@ -299,18 +299,18 @@ previous section means the set of commits reachable from that
 commit, following the commit ancestry chain.
 
 To exclude commits reachable from a commit, a prefix `{caret}`
-notation is used.  E.g. "`{caret}r1 r2`" means commits reachable
+notation is used.  E.g. `{caret}r1 r2` means commits reachable
 from `r2` but exclude the ones reachable from `r1`.
 
 This set operation appears so often that there is a shorthand
 for it.  When you have two commits `r1` and `r2` (named according
 to the syntax explained in SPECIFYING REVISIONS above), you can ask
 for commits that are reachable from r2 excluding those that are reachable
-from r1 by "`{caret}r1 r2`" and it can be written as "`r1..r2`".
+from r1 by `{caret}r1 r2` and it can be written as `r1..r2`.
 
-A similar notation "`r1\...r2`" is called symmetric difference
+A similar notation `r1\...r2` is called symmetric difference
 of `r1` and `r2` and is defined as
-"`r1 r2 --not $(git merge-base --all r1 r2)`".
+`r1 r2 --not $(git merge-base --all r1 r2)`.
 It is the set of commits that are reachable from either one of
 `r1` or `r2` but not from both.
 
index 14dfb501eb2e34523cd3c1e5e11149a07bac3f46..10dfd667b238700f610a51a504876e4c33ad0375 100644 (file)
@@ -60,14 +60,13 @@ The --cc option must be repeated for each user you want on the cc list.
        Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an
        introductory message for the patch series.
 +
-When '--compose' is used, git send-email gets less interactive will use the
-values of the headers you set there. If the body of the email (what you type
-after the headers and a blank line) only contains blank (or GIT: prefixed)
-lines, the summary won't be sent, but git-send-email will still use the
-Headers values if you don't removed them.
+When '--compose' is used, git send-email will use the From, Subject, and
+In-Reply-To headers specified in the message. If the body of the message
+(what you type after the headers and a blank line) only contains blank
+(or GIT: prefixed) lines the summary won't be sent, but From, Subject,
+and In-Reply-To headers will be used unless they are removed.
 +
-If it wasn't able to see a header in the summary it will ask you about it
-interactively after quitting your editor.
+Missing From or In-Reply-To headers will be prompted for.
 
 --from::
        Specify the sender of the emails.  This will default to
index 9a26bde73e695effce9741558994e7799e81489a..7513c57c6a3d4c6dfd853a48f438ee55b9244894 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.6.2/git.html[documentation for release 1.6.2]
+* link:v1.6.2.1/git.html[documentation for release 1.6.2.1]
 
 * release notes for
+  link:RelNotes-1.6.2.1.txt[1.6.2.1],
   link:RelNotes-1.6.2.txt[1.6.2].
 
 * link:v1.6.1.3/git.html[documentation for release 1.6.1.3]
index 29e5929db22257346a2bed16cbd5ca6531698676..be39ed7c1509158867998ce8fb77341242ecdf79 100644 (file)
@@ -46,20 +46,20 @@ Here are the rules regarding the "flags" that you should follow when you are
 scripting git:
 
  * it's preferred to use the non dashed form of git commands, which means that
-   you should prefer `"git foo"` to `"git-foo"`.
+   you should prefer `git foo` to `git-foo`.
 
- * splitting short options to separate words (prefer `"git foo -a -b"`
-   to `"git foo -ab"`, the latter may not even work).
+ * splitting short options to separate words (prefer `git foo -a -b`
+   to `git foo -ab`, the latter may not even work).
 
  * when a command line option takes an argument, use the 'sticked' form.  In
-   other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short
-   options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"`
+   other words, write `git foo -oArg` instead of `git foo -o Arg` for short
+   options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg`
    for long options.  An option that takes optional option-argument must be
    written in the 'sticked' form.
 
  * when you give a revision parameter to a command, make sure the parameter is
    not ambiguous with a name of a file in the work tree.  E.g. do not write
-   `"git log -1 HEAD"` but write `"git log -1 HEAD --"`; the former will not work
+   `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
    if you happen to have a file called `HEAD` in the work tree.
 
 
@@ -99,17 +99,17 @@ usage: git-describe [options] <committish>*
 
 Negating options
 ~~~~~~~~~~~~~~~~
-Options with long option names can be negated by prefixing `"--no-"`. For
-example, `"git branch"` has the option `"--track"` which is 'on' by default. You
-can use `"--no-track"` to override that behaviour. The same goes for `"--color"`
-and `"--no-color"`.
+Options with long option names can be negated by prefixing `--no-`. For
+example, `git branch` has the option `--track` which is 'on' by default. You
+can use `--no-track` to override that behaviour. The same goes for `--color`
+and `--no-color`.
 
 
 Aggregating short options
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 Commands that support the enhanced option parser allow you to aggregate short
-options. This means that you can for example use `"git rm -rf"` or
-`"git clean -fdx"`.
+options. This means that you can for example use `git rm -rf` or
+`git clean -fdx`.
 
 
 Separating argument from the option
index 9afca755ed309b5bdf3cd293d6120f676f1053cd..4fc1cf1184f84b60ee72a9298d23f0464d2edadf 100644 (file)
@@ -262,7 +262,7 @@ This commit is referred to as a "merge commit", or sometimes just a
        'origin' is used for that purpose. New upstream updates
        will be fetched into remote <<def_tracking_branch,tracking branches>> named
        origin/name-of-upstream-branch, which you can see using
-       "`git branch -r`".
+       `git branch -r`.
 
 [[def_pack]]pack::
        A set of objects which have been compressed into one file (to save space
index 96af8977f6cae5382728f13116ea24ba2d130bef..e33b29b1dd58b373a23a939aa2c587b4430b4ff4 100644 (file)
@@ -1136,10 +1136,10 @@ Ignoring files
 A project will often generate files that you do 'not' want to track with git.
 This typically includes files generated by a build process or temporary
 backup files made by your editor. Of course, 'not' tracking files with git
-is just a matter of 'not' calling "`git-add`" on them. But it quickly becomes
+is just a matter of 'not' calling `git-add` on them. But it quickly becomes
 annoying to have these untracked files lying around; e.g. they make
-"`git add .`" practically useless, and they keep showing up in the output of
-"`git status`".
+`git add .` practically useless, and they keep showing up in the output of
+`git status`.
 
 You can tell git to ignore certain files by creating a file called .gitignore
 in the top level of your working directory, with contents such as:
index 1087884be691ed2e9a59dd6289b809496538bf8e..aae3b094116892e54208f0a7198cff4abc0d8b20 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -126,6 +126,12 @@ all::
 # randomly break unless your underlying filesystem supports those sub-second
 # times (my ext3 doesn't).
 #
+# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
+# "st_ctim"
+#
+# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
+# available.  This automatically turns USE_NSEC off.
+#
 # Define USE_STDEV below if you want git to care about the underlying device
 # change being considered an inode change from the update-index perspective.
 #
@@ -657,6 +663,7 @@ ifeq ($(uname_S),Darwin)
        endif
        NO_MEMMEM = YesPlease
        THREADED_DELTA_SEARCH = YesPlease
+       USE_ST_TIMESPEC = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
        NEEDS_SOCKET = YesPlease
@@ -734,6 +741,7 @@ ifeq ($(uname_S),AIX)
        NO_MEMMEM = YesPlease
        NO_MKDTEMP = YesPlease
        NO_STRLCPY = YesPlease
+       NO_NSEC = YesPlease
        FREAD_READS_DIRECTORIES = UnfortunatelyYes
        INTERNAL_QSORT = UnfortunatelyYes
        NEEDS_LIBICONV=YesPlease
@@ -776,7 +784,6 @@ ifneq (,$(findstring CYGWIN,$(uname_S)))
        COMPAT_OBJS += compat/cygwin.o
 endif
 ifneq (,$(findstring MINGW,$(uname_S)))
-       NO_MMAP = YesPlease
        NO_PREAD = YesPlease
        NO_OPENSSL = YesPlease
        NO_CURL = YesPlease
@@ -799,6 +806,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        RUNTIME_PREFIX = YesPlease
        NO_POSIX_ONLY_PROGRAMS = YesPlease
        NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+       NO_NSEC = YesPlease
+       USE_WIN32_MMAP = YesPlease
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
        COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -920,6 +929,15 @@ endif
 ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
        BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
 endif
+ifdef USE_NSEC
+       BASIC_CFLAGS += -DUSE_NSEC
+endif
+ifdef USE_ST_TIMESPEC
+       BASIC_CFLAGS += -DUSE_ST_TIMESPEC
+endif
+ifdef NO_NSEC
+       BASIC_CFLAGS += -DNO_NSEC
+endif
 ifdef NO_C99_FORMAT
        BASIC_CFLAGS += -DNO_C99_FORMAT
 endif
@@ -967,6 +985,11 @@ endif
 ifdef NO_MMAP
        COMPAT_CFLAGS += -DNO_MMAP
        COMPAT_OBJS += compat/mmap.o
+else
+       ifdef USE_WIN32_MMAP
+               COMPAT_CFLAGS += -DUSE_WIN32_MMAP
+               COMPAT_OBJS += compat/win32mmap.o
+       endif
 endif
 ifdef NO_PREAD
        COMPAT_CFLAGS += -DNO_PREAD
@@ -1363,6 +1386,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
 GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
        @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
        @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
+       @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
 
 ### Detect Tck/Tk interpreter path changes
 ifndef NO_TCLTK
index 1f00e44deb28afe74ae4f0b85b23039476032fe5..5f889fee6b94d2aa517c1a694b20772b9fa20507 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -32,21 +32,59 @@ static int find_tracked_branch(struct remote *remote, void *priv)
        return 0;
 }
 
-static int should_setup_rebase(const struct tracking *tracking)
+static int should_setup_rebase(const char *origin)
 {
        switch (autorebase) {
        case AUTOREBASE_NEVER:
                return 0;
        case AUTOREBASE_LOCAL:
-               return tracking->remote == NULL;
+               return origin == NULL;
        case AUTOREBASE_REMOTE:
-               return tracking->remote != NULL;
+               return origin != NULL;
        case AUTOREBASE_ALWAYS:
                return 1;
        }
        return 0;
 }
 
+void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
+{
+       struct strbuf key = STRBUF_INIT;
+       int rebasing = should_setup_rebase(origin);
+
+       strbuf_addf(&key, "branch.%s.remote", local);
+       git_config_set(key.buf, origin ? origin : ".");
+
+       strbuf_reset(&key);
+       strbuf_addf(&key, "branch.%s.merge", local);
+       git_config_set(key.buf, remote);
+
+       if (rebasing) {
+               strbuf_reset(&key);
+               strbuf_addf(&key, "branch.%s.rebase", local);
+               git_config_set(key.buf, "true");
+       }
+
+       if (flag & BRANCH_CONFIG_VERBOSE) {
+               strbuf_reset(&key);
+
+               strbuf_addstr(&key, origin ? "remote" : "local");
+
+               /* Are we tracking a proper "branch"? */
+               if (!prefixcmp(remote, "refs/heads/")) {
+                       strbuf_addf(&key, " branch %s", remote + 11);
+                       if (origin)
+                               strbuf_addf(&key, " from %s", origin);
+               }
+               else
+                       strbuf_addf(&key, " ref %s", remote);
+               printf("Branch %s set up to track %s%s.\n",
+                      local, key.buf,
+                      rebasing ? " by rebasing" : "");
+       }
+       strbuf_release(&key);
+}
+
 /*
  * This is called when new_ref is branched off of orig_ref, and tries
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
@@ -55,7 +93,6 @@ static int should_setup_rebase(const struct tracking *tracking)
 static int setup_tracking(const char *new_ref, const char *orig_ref,
                           enum branch_track track)
 {
-       char key[1024];
        struct tracking tracking;
 
        if (strlen(new_ref) > 1024 - 7 - 7 - 1)
@@ -80,19 +117,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
                return error("Not tracking: ambiguous information for ref %s",
                                orig_ref);
 
-       sprintf(key, "branch.%s.remote", new_ref);
-       git_config_set(key, tracking.remote ?  tracking.remote : ".");
-       sprintf(key, "branch.%s.merge", new_ref);
-       git_config_set(key, tracking.src ? tracking.src : orig_ref);
-       printf("Branch %s set up to track %s branch %s.\n", new_ref,
-               tracking.remote ? "remote" : "local", orig_ref);
-       if (should_setup_rebase(&tracking)) {
-               sprintf(key, "branch.%s.rebase", new_ref);
-               git_config_set(key, "true");
-               printf("This branch will rebase on pull.\n");
-       }
-       free(tracking.src);
+       install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
+                             tracking.src ? tracking.src : orig_ref);
 
+       free(tracking.src);
        return 0;
 }
 
index 9f0c2a2c1fab9a312f436880956da0973c68ead8..eed817a64c7620bfe67f395e39b4eef2f85a4ab3 100644 (file)
--- a/branch.h
+++ b/branch.h
@@ -21,4 +21,11 @@ void create_branch(const char *head, const char *name, const char *start_name,
  */
 void remove_branch_state(void);
 
+/*
+ * Configure local branch "local" to merge remote branch "remote"
+ * taken from origin "origin".
+ */
+#define BRANCH_CONFIG_VERBOSE 01
+extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
+
 #endif
index 08443f2f1ecf7d9edd21cec11fa74548c3326df5..7ddb65932dd6ae11589c5063335b857ecd3298d9 100644 (file)
@@ -148,7 +148,7 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p
        if (pathspec) {
                const char **p;
                for (p = pathspec; *p; p++) {
-                       if (has_symlink_leading_path(strlen(*p), *p)) {
+                       if (has_symlink_leading_path(*p, strlen(*p))) {
                                int len = prefix ? strlen(prefix) : 0;
                                die("'%s' is beyond a symbolic link", *p + len);
                        }
index f312798af38553e0badeda9732736a62460eae05..b52aa20cfaea76f957741d32240a6cb6e161d60e 100644 (file)
@@ -2360,7 +2360,7 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)
                 * In such a case, path "new_name" does not exist as
                 * far as git is concerned.
                 */
-               if (has_symlink_leading_path(strlen(new_name), new_name))
+               if (has_symlink_leading_path(new_name, strlen(new_name)))
                        return 0;
 
                return error("%s: already exists in working directory", new_name);
@@ -3212,7 +3212,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 
        struct option builtin_apply_options[] = {
                { OPTION_CALLBACK, 0, "exclude", NULL, "path",
-                       "don´t apply changes matching the given path",
+                       "don't apply changes matching the given path",
                        0, option_parse_exclude },
                { OPTION_CALLBACK, 0, "include", NULL, "path",
                        "apply changes matching the given path",
@@ -3224,10 +3224,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        "ignore additions made by the patch"),
                OPT_BOOLEAN(0, "stat", &diffstat,
                        "instead of applying the patch, output diffstat for the input"),
-               OPT_BOOLEAN(0, "allow-binary-replacement", &binary,
-                       "now no-op"),
-               OPT_BOOLEAN(0, "binary", &binary,
-                       "now no-op"),
+               { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
+                 NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
+               { OPTION_BOOLEAN, 0, "binary", &binary,
+                 NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
                OPT_BOOLEAN(0, "numstat", &numstat,
                        "shows number of added and deleted lines in decimal notation"),
                OPT_BOOLEAN(0, "summary", &summary,
index 60adef93632ec64c528e443cf1fb3d656a54e36c..ab50cebba0e6798996cc007ced9079c3f0b94a29 100644 (file)
@@ -52,7 +52,7 @@ static int run_remote_archiver(int argc, const char **argv,
                die("git archive: expected a flush");
 
        /* Now, start reading from fd[0] and spit it out to stdout */
-       rv = recv_sideband("archive", fd[0], 1, 2);
+       rv = recv_sideband("archive", fd[0], 1);
        close(fd[0]);
        close(fd[1]);
        rv |= finish_connect(conn);
index 39523cee309f16268130427f8209f9a5be0cdc70..0031b5f51cd96525a265dab02494700e9d36fce8 100644 (file)
@@ -20,6 +20,8 @@
 #include "dir.h"
 #include "pack-refs.h"
 #include "sigchain.h"
+#include "branch.h"
+#include "remote.h"
 #include "run-command.h"
 
 /*
@@ -294,43 +296,6 @@ static void remove_junk_on_signal(int signo)
        raise(signo);
 }
 
-static const struct ref *locate_head(const struct ref *refs,
-                                    const struct ref *mapped_refs,
-                                    const struct ref **remote_head_p)
-{
-       const struct ref *remote_head = NULL;
-       const struct ref *remote_master = NULL;
-       const struct ref *r;
-       for (r = refs; r; r = r->next)
-               if (!strcmp(r->name, "HEAD"))
-                       remote_head = r;
-
-       for (r = mapped_refs; r; r = r->next)
-               if (!strcmp(r->name, "refs/heads/master"))
-                       remote_master = r;
-
-       if (remote_head_p)
-               *remote_head_p = remote_head;
-
-       /* If there's no HEAD value at all, never mind. */
-       if (!remote_head)
-               return NULL;
-
-       /* If refs/heads/master could be right, it is. */
-       if (remote_master && !hashcmp(remote_master->old_sha1,
-                                     remote_head->old_sha1))
-               return remote_master;
-
-       /* Look for another ref that points there */
-       for (r = mapped_refs; r; r = r->next)
-               if (r != remote_head &&
-                   !hashcmp(r->old_sha1, remote_head->old_sha1))
-                       return r;
-
-       /* Nothing is the same */
-       return NULL;
-}
-
 static struct ref *write_remote_refs(const struct ref *refs,
                struct refspec *refspec, const char *reflog)
 {
@@ -351,19 +316,6 @@ static struct ref *write_remote_refs(const struct ref *refs,
        return local_refs;
 }
 
-static void install_branch_config(const char *local,
-                                 const char *origin,
-                                 const char *remote)
-{
-       struct strbuf key = STRBUF_INIT;
-       strbuf_addf(&key, "branch.%s.remote", local);
-       git_config_set(key.buf, origin);
-       strbuf_reset(&key);
-       strbuf_addf(&key, "branch.%s.merge", local);
-       git_config_set(key.buf, remote);
-       strbuf_release(&key);
-}
-
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
        int is_bundle = 0;
@@ -378,7 +330,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        char *src_ref_prefix = "refs/heads/";
        int err = 0;
 
-       struct refspec refspec;
+       struct refspec *refspec;
+       const char *fetch_pattern;
 
        junk_pid = getpid();
 
@@ -483,8 +436,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
        }
 
+       strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
+
        if (option_mirror || !option_bare) {
                /* Configure the remote */
+               strbuf_addf(&key, "remote.%s.fetch", option_origin);
+               git_config_set_multivar(key.buf, value.buf, "^$", 0);
+               strbuf_reset(&key);
+
                if (option_mirror) {
                        strbuf_addf(&key, "remote.%s.mirror", option_origin);
                        git_config_set(key.buf, "true");
@@ -493,19 +452,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
                strbuf_addf(&key, "remote.%s.url", option_origin);
                git_config_set(key.buf, repo);
-                       strbuf_reset(&key);
-
-               strbuf_addf(&key, "remote.%s.fetch", option_origin);
-               strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-               git_config_set_multivar(key.buf, value.buf, "^$", 0);
                strbuf_reset(&key);
-               strbuf_reset(&value);
        }
 
-       refspec.force = 0;
-       refspec.pattern = 1;
-       refspec.src = src_ref_prefix;
-       refspec.dst = branch_top.buf;
+       fetch_pattern = value.buf;
+       refspec = parse_fetch_refspec(1, &fetch_pattern);
+
+       strbuf_reset(&value);
 
        if (path && !is_bundle)
                refs = clone_local(path, git_dir);
@@ -539,9 +492,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (refs) {
                clear_extra_refs();
 
-               mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
+               mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
 
-               head_points_at = locate_head(refs, mapped_refs, &remote_head);
+               remote_head = find_ref_by_name(refs, "HEAD");
+               head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
        }
        else {
                warning("You appear to have cloned an empty repository.");
@@ -549,7 +503,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                remote_head = NULL;
                option_no_checkout = 1;
                if (!option_bare)
-                       install_branch_config("master", option_origin,
+                       install_branch_config(0, "master", option_origin,
                                              "refs/heads/master");
        }
 
@@ -579,7 +533,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                      head_points_at->peer_ref->name,
                                      reflog_msg.buf);
 
-                       install_branch_config(head, option_origin,
+                       install_branch_config(0, head, option_origin,
                                              head_points_at->name);
                }
        } else if (remote_head) {
index d52a05744487182cfcd9e974ad1fb8c65e3eca89..d8da72cf20fa01600b4ad9e6e7a78240b4b4c290 100644 (file)
@@ -1,9 +1,12 @@
 #include "builtin.h"
 #include "cache.h"
 #include "color.h"
+#include "parse-options.h"
 
-static const char git_config_set_usage[] =
-"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty] | --edit | -e ]";
+static const char *const builtin_config_usage[] = {
+       "git config [options]",
+       NULL
+};
 
 static char *key;
 static regex_t *key_regexp;
@@ -16,7 +19,67 @@ static int seen;
 static char delim = '=';
 static char key_delim = ' ';
 static char term = '\n';
-static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
+
+static int use_global_config, use_system_config;
+static const char *given_config_file;
+static int actions, types;
+static const char *get_color_slot, *get_colorbool_slot;
+static int end_null;
+
+#define ACTION_GET (1<<0)
+#define ACTION_GET_ALL (1<<1)
+#define ACTION_GET_REGEXP (1<<2)
+#define ACTION_REPLACE_ALL (1<<3)
+#define ACTION_ADD (1<<4)
+#define ACTION_UNSET (1<<5)
+#define ACTION_UNSET_ALL (1<<6)
+#define ACTION_RENAME_SECTION (1<<7)
+#define ACTION_REMOVE_SECTION (1<<8)
+#define ACTION_LIST (1<<9)
+#define ACTION_EDIT (1<<10)
+#define ACTION_SET (1<<11)
+#define ACTION_SET_ALL (1<<12)
+#define ACTION_GET_COLOR (1<<13)
+#define ACTION_GET_COLORBOOL (1<<14)
+
+#define TYPE_BOOL (1<<0)
+#define TYPE_INT (1<<1)
+#define TYPE_BOOL_OR_INT (1<<2)
+
+static struct option builtin_config_options[] = {
+       OPT_GROUP("Config file location"),
+       OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
+       OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
+       OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"),
+       OPT_GROUP("Action"),
+       OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
+       OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
+       OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP),
+       OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL),
+       OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD),
+       OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET),
+       OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL),
+       OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION),
+       OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION),
+       OPT_BIT('l', "list", &actions, "list all", ACTION_LIST),
+       OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT),
+       OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"),
+       OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"),
+       OPT_GROUP("Type"),
+       OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
+       OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
+       OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
+       OPT_GROUP("Other"),
+       OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
+       OPT_END(),
+};
+
+static void check_argc(int argc, int min, int max) {
+       if (argc >= min && argc <= max)
+               return;
+       error("wrong number of arguments");
+       usage_with_options(builtin_config_usage, builtin_config_options);
+}
 
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
@@ -49,11 +112,11 @@ static int show_config(const char *key_, const char *value_, void *cb)
        }
        if (seen && !do_all)
                dup_error = 1;
-       if (type == T_INT)
+       if (types == TYPE_INT)
                sprintf(value, "%d", git_config_int(key_, value_?value_:""));
-       else if (type == T_BOOL)
+       else if (types == TYPE_BOOL)
                vptr = git_config_bool(key_, value_) ? "true" : "false";
-       else if (type == T_BOOL_OR_INT) {
+       else if (types == TYPE_BOOL_OR_INT) {
                int is_bool, v;
                v = git_config_bool_or_int(key_, value_, &is_bool);
                if (is_bool)
@@ -152,18 +215,18 @@ static char *normalize_value(const char *key, const char *value)
        if (!value)
                return NULL;
 
-       if (type == T_RAW)
+       if (types == 0)
                normalized = xstrdup(value);
        else {
                normalized = xmalloc(64);
-               if (type == T_INT) {
+               if (types == TYPE_INT) {
                        int v = git_config_int(key, value);
                        sprintf(normalized, "%d", v);
                }
-               else if (type == T_BOOL)
+               else if (types == TYPE_BOOL)
                        sprintf(normalized, "%s",
                                git_config_bool(key, value) ? "true" : "false");
-               else if (type == T_BOOL_OR_INT) {
+               else if (types == TYPE_BOOL_OR_INT) {
                        int is_bool, v;
                        v = git_config_bool_or_int(key, value, &is_bool);
                        if (!is_bool)
@@ -178,6 +241,7 @@ static char *normalize_value(const char *key, const char *value)
 
 static int get_color_found;
 static const char *get_color_slot;
+static const char *get_colorbool_slot;
 static char parsed_color[COLOR_MAXLEN];
 
 static int git_get_color_config(const char *var, const char *value, void *cb)
@@ -191,29 +255,8 @@ static int git_get_color_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
-static int get_color(int argc, const char **argv)
+static void get_color(const char *def_color)
 {
-       /*
-        * grab the color setting for the given slot from the configuration,
-        * or parse the default value if missing, and return ANSI color
-        * escape sequence.
-        *
-        * e.g.
-        * git config --get-color color.diff.whitespace "blue reverse"
-        */
-       const char *def_color = NULL;
-
-       switch (argc) {
-       default:
-               usage(git_config_set_usage);
-       case 2:
-               def_color = argv[1];
-               /* fallthru */
-       case 1:
-               get_color_slot = argv[0];
-               break;
-       }
-
        get_color_found = 0;
        parsed_color[0] = '\0';
        git_config(git_get_color_config, NULL);
@@ -222,7 +265,6 @@ static int get_color(int argc, const char **argv)
                color_parse(def_color, "command line", parsed_color);
 
        fputs(parsed_color, stdout);
-       return 0;
 }
 
 static int stdout_is_tty;
@@ -231,7 +273,7 @@ static int get_diff_color_found;
 static int git_get_colorbool_config(const char *var, const char *value,
                void *cb)
 {
-       if (!strcmp(var, get_color_slot)) {
+       if (!strcmp(var, get_colorbool_slot)) {
                get_colorbool_found =
                        git_config_colorbool(var, value, stdout_is_tty);
        }
@@ -246,191 +288,188 @@ static int git_get_colorbool_config(const char *var, const char *value,
        return 0;
 }
 
-static int get_colorbool(int argc, const char **argv)
+static int get_colorbool(int print)
 {
-       /*
-        * git config --get-colorbool <slot> [<stdout-is-tty>]
-        *
-        * returns "true" or "false" depending on how <slot>
-        * is configured.
-        */
-
-       if (argc == 2)
-               stdout_is_tty = git_config_bool("command line", argv[1]);
-       else if (argc == 1)
-               stdout_is_tty = isatty(1);
-       else
-               usage(git_config_set_usage);
        get_colorbool_found = -1;
        get_diff_color_found = -1;
-       get_color_slot = argv[0];
        git_config(git_get_colorbool_config, NULL);
 
        if (get_colorbool_found < 0) {
-               if (!strcmp(get_color_slot, "color.diff"))
+               if (!strcmp(get_colorbool_slot, "color.diff"))
                        get_colorbool_found = get_diff_color_found;
                if (get_colorbool_found < 0)
                        get_colorbool_found = git_use_color_default;
        }
 
-       if (argc == 1) {
-               return get_colorbool_found ? 0 : 1;
-       } else {
+       if (print) {
                printf("%s\n", get_colorbool_found ? "true" : "false");
                return 0;
-       }
+       } else
+               return get_colorbool_found ? 0 : 1;
 }
 
-int cmd_config(int argc, const char **argv, const char *prefix)
+int cmd_config(int argc, const char **argv, const char *unused_prefix)
 {
        int nongit;
        char *value;
-       const char *file = setup_git_directory_gently(&nongit);
+       const char *prefix = setup_git_directory_gently(&nongit);
 
        config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
 
-       while (1 < argc) {
-               if (!strcmp(argv[1], "--int"))
-                       type = T_INT;
-               else if (!strcmp(argv[1], "--bool"))
-                       type = T_BOOL;
-               else if (!strcmp(argv[1], "--bool-or-int"))
-                       type = T_BOOL_OR_INT;
-               else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
-                       if (argc != 2)
-                               usage(git_config_set_usage);
-                       if (git_config(show_all_config, NULL) < 0 &&
-                                       file && errno)
-                               die("unable to read config file %s: %s", file,
-                                   strerror(errno));
-                       return 0;
-               }
-               else if (!strcmp(argv[1], "--global")) {
-                       char *home = getenv("HOME");
-                       if (home) {
-                               char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
-                               config_exclusive_filename = user_config;
-                       } else {
-                               die("$HOME not set");
-                       }
-               }
-               else if (!strcmp(argv[1], "--system"))
-                       config_exclusive_filename = git_etc_gitconfig();
-               else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
-                       if (argc < 3)
-                               usage(git_config_set_usage);
-                       if (!is_absolute_path(argv[2]) && file)
-                               file = prefix_filename(file, strlen(file),
-                                                      argv[2]);
-                       else
-                               file = argv[2];
-                       config_exclusive_filename = file;
-                       argc--;
-                       argv++;
-               }
-               else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
-                       term = '\0';
-                       delim = '\n';
-                       key_delim = '\n';
-               }
-               else if (!strcmp(argv[1], "--rename-section")) {
-                       int ret;
-                       if (argc != 4)
-                               usage(git_config_set_usage);
-                       ret = git_config_rename_section(argv[2], argv[3]);
-                       if (ret < 0)
-                               return ret;
-                       if (ret == 0) {
-                               fprintf(stderr, "No such section!\n");
-                               return 1;
-                       }
-                       return 0;
-               }
-               else if (!strcmp(argv[1], "--remove-section")) {
-                       int ret;
-                       if (argc != 3)
-                               usage(git_config_set_usage);
-                       ret = git_config_rename_section(argv[2], NULL);
-                       if (ret < 0)
-                               return ret;
-                       if (ret == 0) {
-                               fprintf(stderr, "No such section!\n");
-                               return 1;
-                       }
-                       return 0;
-               } else if (!strcmp(argv[1], "--get-color")) {
-                       return get_color(argc-2, argv+2);
-               } else if (!strcmp(argv[1], "--get-colorbool")) {
-                       return get_colorbool(argc-2, argv+2);
-               } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) {
-                       if (argc != 2)
-                               usage(git_config_set_usage);
-                       git_config(git_default_config, NULL);
-                       launch_editor(config_exclusive_filename ?
-                                     config_exclusive_filename : git_path("config"),
-                                     NULL, NULL);
-                       return 0;
-               } else
-                       break;
-               argc--;
-               argv++;
-       }
-
-       switch (argc) {
-       case 2:
-               return get_value(argv[1], NULL);
-       case 3:
-               if (!strcmp(argv[1], "--unset"))
-                       return git_config_set(argv[2], NULL);
-               else if (!strcmp(argv[1], "--unset-all"))
-                       return git_config_set_multivar(argv[2], NULL, NULL, 1);
-               else if (!strcmp(argv[1], "--get"))
-                       return get_value(argv[2], NULL);
-               else if (!strcmp(argv[1], "--get-all")) {
-                       do_all = 1;
-                       return get_value(argv[2], NULL);
-               } else if (!strcmp(argv[1], "--get-regexp")) {
-                       show_keys = 1;
-                       use_key_regexp = 1;
-                       do_all = 1;
-                       return get_value(argv[2], NULL);
+       argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (use_global_config + use_system_config + !!given_config_file > 1) {
+               error("only one config file at a time.");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
+
+       if (use_global_config) {
+               char *home = getenv("HOME");
+               if (home) {
+                       char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
+                       config_exclusive_filename = user_config;
                } else {
-                       value = normalize_value(argv[1], argv[2]);
-                       return git_config_set(argv[1], value);
+                       die("$HOME not set");
                }
-       case 4:
-               if (!strcmp(argv[1], "--unset"))
-                       return git_config_set_multivar(argv[2], NULL, argv[3], 0);
-               else if (!strcmp(argv[1], "--unset-all"))
-                       return git_config_set_multivar(argv[2], NULL, argv[3], 1);
-               else if (!strcmp(argv[1], "--get"))
-                       return get_value(argv[2], argv[3]);
-               else if (!strcmp(argv[1], "--get-all")) {
-                       do_all = 1;
-                       return get_value(argv[2], argv[3]);
-               } else if (!strcmp(argv[1], "--get-regexp")) {
-                       show_keys = 1;
-                       use_key_regexp = 1;
-                       do_all = 1;
-                       return get_value(argv[2], argv[3]);
-               } else if (!strcmp(argv[1], "--add")) {
-                       value = normalize_value(argv[2], argv[3]);
-                       return git_config_set_multivar(argv[2], value, "^$", 0);
-               } else if (!strcmp(argv[1], "--replace-all")) {
-                       value = normalize_value(argv[2], argv[3]);
-                       return git_config_set_multivar(argv[2], value, NULL, 1);
-               } else {
-                       value = normalize_value(argv[1], argv[2]);
-                       return git_config_set_multivar(argv[1], value, argv[3], 0);
+       }
+       else if (use_system_config)
+               config_exclusive_filename = git_etc_gitconfig();
+       else if (given_config_file) {
+               if (!is_absolute_path(given_config_file) && prefix)
+                       config_exclusive_filename = prefix_filename(prefix,
+                                                                   strlen(prefix),
+                                                                   argv[2]);
+               else
+                       config_exclusive_filename = given_config_file;
+       }
+
+       if (end_null) {
+               term = '\0';
+               delim = '\n';
+               key_delim = '\n';
+       }
+
+       if (HAS_MULTI_BITS(types)) {
+               error("only one type at a time.");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
+
+       if (get_color_slot)
+           actions |= ACTION_GET_COLOR;
+       if (get_colorbool_slot)
+           actions |= ACTION_GET_COLORBOOL;
+
+       if ((get_color_slot || get_colorbool_slot) && types) {
+               error("--get-color and variable type are incoherent");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
+
+       if (HAS_MULTI_BITS(actions)) {
+               error("only one action at a time.");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
+       if (actions == 0)
+               switch (argc) {
+               case 1: actions = ACTION_GET; break;
+               case 2: actions = ACTION_SET; break;
+               case 3: actions = ACTION_SET_ALL; break;
+               default:
+                       usage_with_options(builtin_config_usage, builtin_config_options);
                }
-       case 5:
-               if (!strcmp(argv[1], "--replace-all")) {
-                       value = normalize_value(argv[2], argv[3]);
-                       return git_config_set_multivar(argv[2], value, argv[4], 1);
+
+       if (actions == ACTION_LIST) {
+               check_argc(argc, 0, 0);
+               if (git_config(show_all_config, NULL) < 0) {
+                       if (config_exclusive_filename)
+                               die("unable to read config file %s: %s",
+                                   config_exclusive_filename, strerror(errno));
+                       else
+                               die("error processing config file(s)");
                }
-       case 1:
-       default:
-               usage(git_config_set_usage);
        }
+       else if (actions == ACTION_EDIT) {
+               check_argc(argc, 0, 0);
+               git_config(git_default_config, NULL);
+               launch_editor(config_exclusive_filename ?
+                             config_exclusive_filename : git_path("config"),
+                             NULL, NULL);
+       }
+       else if (actions == ACTION_SET) {
+               check_argc(argc, 2, 2);
+               value = normalize_value(argv[0], argv[1]);
+               return git_config_set(argv[0], value);
+       }
+       else if (actions == ACTION_SET_ALL) {
+               check_argc(argc, 2, 3);
+               value = normalize_value(argv[0], argv[1]);
+               return git_config_set_multivar(argv[0], value, argv[2], 0);
+       }
+       else if (actions == ACTION_ADD) {
+               check_argc(argc, 2, 2);
+               value = normalize_value(argv[0], argv[1]);
+               return git_config_set_multivar(argv[0], value, "^$", 0);
+       }
+       else if (actions == ACTION_REPLACE_ALL) {
+               check_argc(argc, 2, 3);
+               value = normalize_value(argv[0], argv[1]);
+               return git_config_set_multivar(argv[0], value, argv[2], 1);
+       }
+       else if (actions == ACTION_GET) {
+               check_argc(argc, 1, 2);
+               return get_value(argv[0], argv[1]);
+       }
+       else if (actions == ACTION_GET_ALL) {
+               do_all = 1;
+               check_argc(argc, 1, 2);
+               return get_value(argv[0], argv[1]);
+       }
+       else if (actions == ACTION_GET_REGEXP) {
+               show_keys = 1;
+               use_key_regexp = 1;
+               do_all = 1;
+               check_argc(argc, 1, 2);
+               return get_value(argv[0], argv[1]);
+       }
+       else if (actions == ACTION_UNSET) {
+               check_argc(argc, 1, 2);
+               if (argc == 2)
+                       return git_config_set_multivar(argv[0], NULL, argv[1], 0);
+               else
+                       return git_config_set(argv[0], NULL);
+       }
+       else if (actions == ACTION_UNSET_ALL) {
+               check_argc(argc, 1, 2);
+               return git_config_set_multivar(argv[0], NULL, argv[1], 1);
+       }
+       else if (actions == ACTION_RENAME_SECTION) {
+               int ret;
+               check_argc(argc, 2, 2);
+               ret = git_config_rename_section(argv[0], argv[1]);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0)
+                       die("No such section!");
+       }
+       else if (actions == ACTION_REMOVE_SECTION) {
+               int ret;
+               check_argc(argc, 1, 1);
+               ret = git_config_rename_section(argv[0], NULL);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0)
+                       die("No such section!");
+       }
+       else if (actions == ACTION_GET_COLOR) {
+               get_color(argv[0]);
+       }
+       else if (actions == ACTION_GET_COLORBOOL) {
+               if (argc == 1)
+                       stdout_is_tty = git_config_bool("command line", argv[0]);
+               else if (argc == 0)
+                       stdout_is_tty = isatty(1);
+               return get_colorbool(argc != 0);
+       }
+
        return 0;
 }
index 8ecefd4f0f99117534deb9ca7d4446ade5c00223..79cedb72c44dca3edf400d86e401a93531b54407 100644 (file)
@@ -102,7 +102,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 
        init_revisions(opt, prefix);
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
-       nr_sha1 = 0;
        opt->abbrev = 0;
        opt->diff = 1;
        argc = setup_revisions(argc, argv, opt, NULL);
index c2e5adc8847e8ffa94bd009121b7a295f3f0512e..d571253a56c80e0b644b220c870b27726c8f3dfc 100644 (file)
@@ -482,7 +482,7 @@ static int sideband_demux(int fd, void *data)
 {
        int *xd = data;
 
-       return recv_sideband("fetch-pack", xd[0], fd, 2);
+       return recv_sideband("fetch-pack", xd[0], fd);
 }
 
 static int get_pack(int xd[2], char **pack_lockfile)
@@ -800,15 +800,13 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                int fd;
 
                mtime.sec = st.st_mtime;
-#ifdef USE_NSEC
-               mtime.usec = st.st_mtim.usec;
-#endif
+               mtime.nsec = ST_MTIME_NSEC(st);
                if (stat(shallow, &st)) {
                        if (mtime.sec)
                                die("shallow file was removed during fetch");
                } else if (st.st_mtime != mtime.sec
 #ifdef USE_NSEC
-                               || st.st_mtim.usec != mtime.usec
+                               || ST_MTIME_NSEC(st) != mtime.nsec
 #endif
                          )
                        die("shallow file was changed during fetch");
index 1e4a3d9c516c88d701819b7f4b73c722412d540f..7fb35fca9d1b57dacaebfd3cb9b2af4d035e750c 100644 (file)
@@ -636,6 +636,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        else
                remote = remote_get(argv[0]);
 
+       if (!remote)
+               die("Where do you want to fetch from today?");
+
        transport = transport_get(remote, remote->url[0]);
        if (verbosity >= 2)
                transport->verbose = 1;
@@ -648,9 +651,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        if (depth)
                set_option(TRANS_OPT_DEPTH, depth);
 
-       if (!transport->url)
-               die("Where do you want to fetch from today?");
-
        if (argc > 1) {
                int j = 0;
                refs = xcalloc(argc + 1, sizeof(const char *));
index e46b7adc9719e147536398e8e365d6d3e65a4ba7..5cbb4b081d63b52393a5f85716ba6961a18fa59e 100644 (file)
@@ -943,7 +943,6 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
                return -1;
 
        *sort_tail = s = xcalloc(1, sizeof(*s));
-       sort_tail = &s->next;
 
        if (*arg == '-') {
                s->reverse = 1;
index 8d990ed4935804591a17c864e280c0c9b4b7597f..fc556ed7f3fb68734fd783e5b38e6b050bed9c5b 100644 (file)
@@ -23,7 +23,7 @@ static const char * const builtin_gc_usage[] = {
 };
 
 static int pack_refs = 1;
-static int aggressive_window = -1;
+static int aggressive_window = 250;
 static int gc_auto_threshold = 6700;
 static int gc_auto_pack_limit = 50;
 static const char *prune_expire = "2.weeks.ago";
@@ -200,6 +200,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 
        if (aggressive) {
                append_option(argv_repack, "-f", MAX_ADD);
+               append_option(argv_repack, "--depth=250", MAX_ADD);
                if (aggressive_window > 0) {
                        sprintf(buf, "--window=%d", aggressive_window);
                        append_option(argv_repack, buf, MAX_ADD);
index 3f12ba382690699d96580c3ddb1a61c79520e694..89489ddcf8edb85160036b0336ab4ce80c3cb6bc 100644 (file)
 
 static int builtin_grep;
 
+static int grep_config(const char *var, const char *value, void *cb)
+{
+       struct grep_opt *opt = cb;
+
+       if (!strcmp(var, "grep.color") || !strcmp(var, "color.grep")) {
+               opt->color = git_config_colorbool(var, value, -1);
+               return 0;
+       }
+       if (!strcmp(var, "grep.color.external") ||
+           !strcmp(var, "color.grep.external")) {
+               return git_config_string(&(opt->color_external), var, value);
+       }
+       if (!strcmp(var, "grep.color.match") ||
+           !strcmp(var, "color.grep.match")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               color_parse(value, var, opt->color_match);
+               return 0;
+       }
+       return git_color_default_config(var, value, cb);
+}
+
 /*
  * git grep pathspecs are somewhat different from diff-tree pathspecs;
  * pathname wildcards are allowed.
@@ -269,6 +291,21 @@ static int flush_grep(struct grep_opt *opt,
        return status;
 }
 
+static void grep_add_color(struct strbuf *sb, const char *escape_seq)
+{
+       size_t orig_len = sb->len;
+
+       while (*escape_seq) {
+               if (*escape_seq == 'm')
+                       strbuf_addch(sb, ';');
+               else if (*escape_seq != '\033' && *escape_seq  != '[')
+                       strbuf_addch(sb, *escape_seq);
+               escape_seq++;
+       }
+       if (sb->len > orig_len && sb->buf[sb->len - 1] == ';')
+               strbuf_setlen(sb, sb->len - 1);
+}
+
 static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 {
        int i, nr, argc, hit, len, status;
@@ -339,6 +376,23 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
                push_arg("-e");
                push_arg(p->pattern);
        }
+       if (opt->color) {
+               struct strbuf sb = STRBUF_INIT;
+
+               grep_add_color(&sb, opt->color_match);
+               setenv("GREP_COLOR", sb.buf, 1);
+
+               strbuf_reset(&sb);
+               strbuf_addstr(&sb, "mt=");
+               grep_add_color(&sb, opt->color_match);
+               strbuf_addstr(&sb, ":sl=:cx=:fn=:ln=:bn=:se=");
+               setenv("GREP_COLORS", sb.buf, 1);
+
+               strbuf_release(&sb);
+
+               if (opt->color_external && strlen(opt->color_external) > 0)
+                       push_arg(opt->color_external);
+       }
 
        hit = 0;
        argc = nr;
@@ -536,6 +590,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        opt.pattern_tail = &opt.pattern_list;
        opt.regflags = REG_NEWLINE;
 
+       strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD);
+       opt.color = -1;
+       git_config(grep_config, &opt);
+       if (opt.color == -1)
+               opt.color = git_use_color_default;
+
        /*
         * If there is no -- then the paths must exist in the working
         * tree.  If there is no explicit pattern specified with -e or
@@ -732,6 +792,14 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        opt.relative = 0;
                        continue;
                }
+               if (!strcmp("--color", arg)) {
+                       opt.color = 1;
+                       continue;
+               }
+               if (!strcmp("--no-color", arg)) {
+                       opt.color = 0;
+                       continue;
+               }
                if (!strcmp("--", arg)) {
                        /* later processing wants to have this at argv[1] */
                        argv--;
@@ -757,6 +825,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                }
        }
 
+       if (opt.color && !opt.color_external)
+               builtin_grep = 1;
        if (!opt.pattern_list)
                die("no pattern given.");
        if ((opt.regflags != REG_NEWLINE) && opt.fixed)
index 8684fcdb67fc0216ffc860f60f5c060f10907b83..8af55d28793ae1fb7180198fb4f63eb7783c6335 100644 (file)
@@ -573,7 +573,7 @@ static FILE *realstdout = NULL;
 static const char *output_directory = NULL;
 static int outdir_offset;
 
-static int reopen_stdout(const char *oneline, int nr, int total)
+static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev)
 {
        char filename[PATH_MAX];
        int len = 0;
@@ -598,7 +598,9 @@ static int reopen_stdout(const char *oneline, int nr, int total)
                strcpy(filename + len, fmt_patch_suffix);
        }
 
-       fprintf(realstdout, "%s\n", filename + outdir_offset);
+       if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
+               fprintf(realstdout, "%s\n", filename + outdir_offset);
+
        if (freopen(filename, "w", stdout) == NULL)
                return error("Cannot open patch file %s",filename);
 
@@ -687,7 +689,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
                die("Cover letter needs email format");
 
        if (!use_stdout && reopen_stdout(numbered_files ?
-                               NULL : "cover-letter", 0, rev->total))
+                               NULL : "cover-letter", 0, rev))
                return;
 
        head_sha1 = sha1_to_hex(head->object.sha1);
@@ -1106,7 +1108,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                }
                if (!use_stdout && reopen_stdout(numbered_files ? NULL :
                                get_oneline_for_filename(commit, keep_subject),
-                               rev.nr, rev.total))
+                               rev.nr, &rev))
                        die("Failed to create output files");
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
index 9dec282fba6ba22e37d13bdc5e35fa4a031433b5..ca6f33d0466572863db7dbd4c3079dcb06caa4e0 100644 (file)
@@ -419,6 +419,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                }
                if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
                        show_deleted = 1;
+                       require_work_tree = 1;
                        continue;
                }
                if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
index fca46312f681caf077565fb4bd5b59a70008eb59..22008dfa8fb94d971b6fb1bd7342ede02a8d3fd0 100644 (file)
@@ -60,7 +60,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
 {
        int retval = 0;
        const char *type = blob_type;
-       unsigned long size;
 
        if (S_ISGITLINK(mode)) {
                /*
@@ -90,17 +89,20 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
 
        if (!(ls_options & LS_NAME_ONLY)) {
                if (ls_options & LS_SHOW_SIZE) {
+                       char size_text[24];
                        if (!strcmp(type, blob_type)) {
-                               sha1_object_info(sha1, &size);
-                               printf("%06o %s %s %7lu\t", mode, type,
-                                      abbrev ? find_unique_abbrev(sha1, abbrev)
-                                             : sha1_to_hex(sha1),
-                                      size);
+                               unsigned long size;
+                               if (sha1_object_info(sha1, &size) == OBJ_BAD)
+                                       strcpy(size_text, "BAD");
+                               else
+                                       snprintf(size_text, sizeof(size_text),
+                                                "%lu", size);
                        } else
-                               printf("%06o %s %s %7c\t", mode, type,
-                                      abbrev ? find_unique_abbrev(sha1, abbrev)
-                                             : sha1_to_hex(sha1),
-                                      '-');
+                               strcpy(size_text, "-");
+                       printf("%06o %s %s %7s\t", mode, type,
+                              abbrev ? find_unique_abbrev(sha1, abbrev)
+                                     : sha1_to_hex(sha1),
+                              size_text);
                } else
                        printf("%06o %s %s\t", mode, type,
                               abbrev ? find_unique_abbrev(sha1, abbrev)
index 2789ccdf7dd43a1170a1ca28a3e4d4802422e719..1eeeb4de6d0d54e3fd753b7f057351094e10a24e 100644 (file)
@@ -537,7 +537,6 @@ static int decode_header_bq(struct strbuf *it)
                                 */
                                strbuf_add(&outbuf, in, ep - in);
                        }
-                       in = ep;
                }
                /* E.g.
                 * ep : "=?iso-2022-jp?B?GyR...?= foo"
index 122fdcfbdc13a11388a091e5ec33d077648fab0a..ca36fb1e5834fc581bc7bf8ed54184bbecdc2389 100644 (file)
@@ -53,8 +53,11 @@ static int do_push(const char *repo, int flags)
        int i, errs;
        struct remote *remote = remote_get(repo);
 
-       if (!remote)
-               die("bad repository '%s'", repo);
+       if (!remote) {
+               if (repo)
+                       die("bad repository '%s'", repo);
+               die("No destination configured to push to.");
+       }
 
        if (remote->mirror)
                flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
index e171096ece8cd041f7e6a08ca80af444786b50cc..993acd6a09869e23b3f8e67f0dddbddc946e6c5f 100644 (file)
@@ -12,12 +12,17 @@ static const char * const builtin_remote_usage[] = {
        "git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
        "git remote rename <old> <new>",
        "git remote rm <name>",
+       "git remote set-head <name> [-a | -d | <branch>]",
        "git remote show [-n] <name>",
        "git remote prune [-n | --dry-run] <name>",
        "git remote [-v | --verbose] update [group]",
        NULL
 };
 
+#define GET_REF_STATES (1<<0)
+#define GET_HEAD_NAMES (1<<1)
+#define GET_PUSH_REF_STATES (1<<2)
+
 static int verbose;
 
 static int show_all(void);
@@ -143,8 +148,9 @@ static int add(int argc, const char **argv)
 }
 
 struct branch_info {
-       char *remote;
+       char *remote_name;
        struct string_list merge;
+       int rebase;
 };
 
 static struct string_list branch_list;
@@ -161,10 +167,11 @@ static const char *abbrev_ref(const char *name, const char *prefix)
 static int config_read_branches(const char *key, const char *value, void *cb)
 {
        if (!prefixcmp(key, "branch.")) {
+               const char *orig_key = key;
                char *name;
                struct string_list_item *item;
                struct branch_info *info;
-               enum { REMOTE, MERGE } type;
+               enum { REMOTE, MERGE, REBASE } type;
 
                key += 7;
                if (!postfixcmp(key, ".remote")) {
@@ -173,6 +180,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)
                } else if (!postfixcmp(key, ".merge")) {
                        name = xstrndup(key, strlen(key) - 6);
                        type = MERGE;
+               } else if (!postfixcmp(key, ".rebase")) {
+                       name = xstrndup(key, strlen(key) - 7);
+                       type = REBASE;
                } else
                        return 0;
 
@@ -182,10 +192,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
                        item->util = xcalloc(sizeof(struct branch_info), 1);
                info = item->util;
                if (type == REMOTE) {
-                       if (info->remote)
-                               warning("more than one branch.%s", key);
-                       info->remote = xstrdup(value);
-               } else {
+                       if (info->remote_name)
+                               warning("more than one %s", orig_key);
+                       info->remote_name = xstrdup(value);
+               } else if (type == MERGE) {
                        char *space = strchr(value, ' ');
                        value = abbrev_branch(value);
                        while (space) {
@@ -196,7 +206,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
                                space = strchr(value, ' ');
                        }
                        string_list_append(xstrdup(value), &info->merge);
-               }
+               } else
+                       info->rebase = git_config_bool(orig_key, value);
        }
        return 0;
 }
@@ -206,12 +217,12 @@ static void read_branches(void)
        if (branch_list.nr)
                return;
        git_config(config_read_branches, NULL);
-       sort_string_list(&branch_list);
 }
 
 struct ref_states {
        struct remote *remote;
-       struct string_list new, stale, tracked;
+       struct string_list new, stale, tracked, heads, push;
+       int queried;
 };
 
 static int handle_one_branch(const char *refname,
@@ -227,10 +238,8 @@ static int handle_one_branch(const char *refname,
                const char *name = abbrev_branch(refspec.src);
                /* symbolic refs pointing nowhere were handled already */
                if ((flags & REF_ISSYMREF) ||
-                               unsorted_string_list_has_string(&states->tracked,
-                                       name) ||
-                               unsorted_string_list_has_string(&states->new,
-                                       name))
+                   string_list_has_string(&states->tracked, name) ||
+                   string_list_has_string(&states->new, name))
                        return 0;
                item = string_list_append(name, &states->stale);
                item->util = xstrdup(refname);
@@ -238,39 +247,154 @@ static int handle_one_branch(const char *refname,
        return 0;
 }
 
-static int get_ref_states(const struct ref *ref, struct ref_states *states)
+static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
 {
        struct ref *fetch_map = NULL, **tail = &fetch_map;
+       struct ref *ref;
        int i;
 
        for (i = 0; i < states->remote->fetch_refspec_nr; i++)
-               if (get_fetch_map(ref, states->remote->fetch + i, &tail, 1))
+               if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))
                        die("Could not get fetch map for refspec %s",
                                states->remote->fetch_refspec[i]);
 
        states->new.strdup_strings = states->tracked.strdup_strings = 1;
        for (ref = fetch_map; ref; ref = ref->next) {
-               struct string_list *target = &states->tracked;
                unsigned char sha1[20];
-               void *util = NULL;
-
                if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))
-                       target = &states->new;
-               else {
-                       target = &states->tracked;
-                       if (hashcmp(sha1, ref->new_sha1))
-                               util = &states;
-               }
-               string_list_append(abbrev_branch(ref->name), target)->util = util;
+                       string_list_append(abbrev_branch(ref->name), &states->new);
+               else
+                       string_list_append(abbrev_branch(ref->name), &states->tracked);
        }
        free_refs(fetch_map);
 
+       sort_string_list(&states->new);
+       sort_string_list(&states->tracked);
        for_each_ref(handle_one_branch, states);
        sort_string_list(&states->stale);
 
        return 0;
 }
 
+struct push_info {
+       char *dest;
+       int forced;
+       enum {
+               PUSH_STATUS_CREATE = 0,
+               PUSH_STATUS_DELETE,
+               PUSH_STATUS_UPTODATE,
+               PUSH_STATUS_FASTFORWARD,
+               PUSH_STATUS_OUTOFDATE,
+               PUSH_STATUS_NOTQUERIED,
+       } status;
+};
+
+static int get_push_ref_states(const struct ref *remote_refs,
+       struct ref_states *states)
+{
+       struct remote *remote = states->remote;
+       struct ref *ref, *local_refs, *push_map, **push_tail;
+       if (remote->mirror)
+               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;
+
+       match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,
+                  remote->push_refspec, MATCH_REFS_NONE);
+
+       states->push.strdup_strings = 1;
+       for (ref = push_map; ref; ref = ref->next) {
+               struct string_list_item *item;
+               struct push_info *info;
+
+               if (!ref->peer_ref)
+                       continue;
+               hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
+
+               item = string_list_append(abbrev_branch(ref->peer_ref->name),
+                                         &states->push);
+               item->util = xcalloc(sizeof(struct push_info), 1);
+               info = item->util;
+               info->forced = ref->force;
+               info->dest = xstrdup(abbrev_branch(ref->name));
+
+               if (is_null_sha1(ref->new_sha1)) {
+                       info->status = PUSH_STATUS_DELETE;
+               } else if (!hashcmp(ref->old_sha1, ref->new_sha1))
+                       info->status = PUSH_STATUS_UPTODATE;
+               else if (is_null_sha1(ref->old_sha1))
+                       info->status = PUSH_STATUS_CREATE;
+               else if (has_sha1_file(ref->old_sha1) &&
+                        ref_newer(ref->new_sha1, ref->old_sha1))
+                       info->status = PUSH_STATUS_FASTFORWARD;
+               else
+                       info->status = PUSH_STATUS_OUTOFDATE;
+       }
+       free_refs(local_refs);
+       free_refs(push_map);
+       return 0;
+}
+
+static int get_push_ref_states_noquery(struct ref_states *states)
+{
+       int i;
+       struct remote *remote = states->remote;
+       struct string_list_item *item;
+       struct push_info *info;
+
+       if (remote->mirror)
+               return 0;
+
+       states->push.strdup_strings = 1;
+       if (!remote->push_refspec_nr) {
+               item = string_list_append("(matching)", &states->push);
+               info = item->util = xcalloc(sizeof(struct push_info), 1);
+               info->status = PUSH_STATUS_NOTQUERIED;
+               info->dest = xstrdup(item->string);
+       }
+       for (i = 0; i < remote->push_refspec_nr; i++) {
+               struct refspec *spec = remote->push + i;
+               if (spec->matching)
+                       item = string_list_append("(matching)", &states->push);
+               else if (strlen(spec->src))
+                       item = string_list_append(spec->src, &states->push);
+               else
+                       item = string_list_append("(delete)", &states->push);
+
+               info = item->util = xcalloc(sizeof(struct push_info), 1);
+               info->forced = spec->force;
+               info->status = PUSH_STATUS_NOTQUERIED;
+               info->dest = xstrdup(spec->dst ? spec->dst : item->string);
+       }
+       return 0;
+}
+
+static int get_head_names(const struct ref *remote_refs, struct ref_states *states)
+{
+       struct ref *ref, *matches;
+       struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
+       struct refspec refspec;
+
+       refspec.force = 0;
+       refspec.pattern = 1;
+       refspec.src = refspec.dst = "refs/heads/*";
+       states->heads.strdup_strings = 1;
+       get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
+       matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
+                                   fetch_map, 1);
+       for(ref = matches; ref; ref = ref->next)
+               string_list_append(abbrev_branch(ref->name), &states->heads);
+
+       free_refs(fetch_map);
+       free_refs(matches);
+
+       return 0;
+}
+
 struct known_remote {
        struct known_remote *next;
        struct remote *remote;
@@ -466,7 +590,7 @@ static int mv(int argc, const char **argv)
        for (i = 0; i < branch_list.nr; i++) {
                struct string_list_item *item = branch_list.items + i;
                struct branch_info *info = item->util;
-               if (info->remote && !strcmp(info->remote, rename.old)) {
+               if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
                        strbuf_reset(&buf);
                        strbuf_addf(&buf, "branch.%s.remote", item->string);
                        if (git_config_set(buf.buf, rename.new)) {
@@ -575,7 +699,7 @@ static int rm(int argc, const char **argv)
        for (i = 0; i < branch_list.nr; i++) {
                struct string_list_item *item = branch_list.items + i;
                struct branch_info *info = item->util;
-               if (info->remote && !strcmp(info->remote, remote->name)) {
+               if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
                        const char *keys[] = { "remote", "merge", NULL }, **k;
                        for (k = keys; *k; k++) {
                                strbuf_reset(&buf);
@@ -617,18 +741,37 @@ static int rm(int argc, const char **argv)
        return result;
 }
 
-static void show_list(const char *title, struct string_list *list,
-                     const char *extra_arg)
+void clear_push_info(void *util, const char *string)
 {
-       int i;
+       struct push_info *info = util;
+       free(info->dest);
+       free(info);
+}
 
-       if (!list->nr)
-               return;
+static void free_remote_ref_states(struct ref_states *states)
+{
+       string_list_clear(&states->new, 0);
+       string_list_clear(&states->stale, 0);
+       string_list_clear(&states->tracked, 0);
+       string_list_clear(&states->heads, 0);
+       string_list_clear_func(&states->push, clear_push_info);
+}
 
-       printf(title, list->nr > 1 ? "es" : "", extra_arg);
-       printf("\n");
-       for (i = 0; i < list->nr; i++)
-               printf("    %s\n", list->items[i].string);
+static int append_ref_to_tracked_list(const char *refname,
+       const unsigned char *sha1, int flags, void *cb_data)
+{
+       struct ref_states *states = cb_data;
+       struct refspec refspec;
+
+       if (flags & REF_ISSYMREF)
+               return 0;
+
+       memset(&refspec, 0, sizeof(refspec));
+       refspec.dst = (char *)refname;
+       if (!remote_find_tracking(states->remote, &refspec))
+               string_list_append(abbrev_branch(refspec.src), &states->tracked);
+
+       return 0;
 }
 
 static int get_remote_ref_states(const char *name,
@@ -636,7 +779,7 @@ static int get_remote_ref_states(const char *name,
                                 int query)
 {
        struct transport *transport;
-       const struct ref *ref;
+       const struct ref *remote_refs;
 
        states->remote = remote_get(name);
        if (!states->remote)
@@ -647,102 +790,318 @@ static int get_remote_ref_states(const char *name,
        if (query) {
                transport = transport_get(NULL, states->remote->url_nr > 0 ?
                        states->remote->url[0] : NULL);
-               ref = transport_get_remote_refs(transport);
+               remote_refs = transport_get_remote_refs(transport);
                transport_disconnect(transport);
 
-               get_ref_states(ref, states);
+               states->queried = 1;
+               if (query & GET_REF_STATES)
+                       get_ref_states(remote_refs, states);
+               if (query & GET_HEAD_NAMES)
+                       get_head_names(remote_refs, states);
+               if (query & GET_PUSH_REF_STATES)
+                       get_push_ref_states(remote_refs, states);
+       } else {
+               for_each_ref(append_ref_to_tracked_list, states);
+               sort_string_list(&states->tracked);
+               get_push_ref_states_noquery(states);
        }
 
        return 0;
 }
 
-static int append_ref_to_tracked_list(const char *refname,
-       const unsigned char *sha1, int flags, void *cb_data)
+struct show_info {
+       struct string_list *list;
+       struct ref_states *states;
+       int width, width2;
+       int any_rebase;
+};
+
+int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
 {
-       struct ref_states *states = cb_data;
-       struct refspec refspec;
+       struct show_info *info = cb_data;
+       int n = strlen(item->string);
+       if (n > info->width)
+               info->width = n;
+       string_list_insert(item->string, info->list);
+       return 0;
+}
 
-       memset(&refspec, 0, sizeof(refspec));
-       refspec.dst = (char *)refname;
-       if (!remote_find_tracking(states->remote, &refspec))
-               string_list_append(abbrev_branch(refspec.src), &states->tracked);
+int show_remote_info_item(struct string_list_item *item, void *cb_data)
+{
+       struct show_info *info = cb_data;
+       struct ref_states *states = info->states;
+       const char *name = item->string;
+
+       if (states->queried) {
+               const char *fmt = "%s";
+               const char *arg = "";
+               if (string_list_has_string(&states->new, name)) {
+                       fmt = " new (next fetch will store in remotes/%s)";
+                       arg = states->remote->name;
+               } else if (string_list_has_string(&states->tracked, name))
+                       arg = " tracked";
+               else if (string_list_has_string(&states->stale, name))
+                       arg = " stale (use 'git remote prune' to remove)";
+               else
+                       arg = " ???";
+               printf("    %-*s", info->width, name);
+               printf(fmt, arg);
+               printf("\n");
+       } else
+               printf("    %s\n", name);
+
+       return 0;
+}
+
+int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
+{
+       struct show_info *show_info = cb_data;
+       struct ref_states *states = show_info->states;
+       struct branch_info *branch_info = branch_item->util;
+       struct string_list_item *item;
+       int n;
+
+       if (!branch_info->merge.nr || !branch_info->remote_name ||
+           strcmp(states->remote->name, branch_info->remote_name))
+               return 0;
+       if ((n = strlen(branch_item->string)) > show_info->width)
+               show_info->width = n;
+       if (branch_info->rebase)
+               show_info->any_rebase = 1;
+
+       item = string_list_insert(branch_item->string, show_info->list);
+       item->util = branch_info;
+
+       return 0;
+}
+
+int show_local_info_item(struct string_list_item *item, void *cb_data)
+{
+       struct show_info *show_info = cb_data;
+       struct branch_info *branch_info = item->util;
+       struct string_list *merge = &branch_info->merge;
+       const char *also;
+       int i;
+
+       if (branch_info->rebase && branch_info->merge.nr > 1) {
+               error("invalid branch.%s.merge; cannot rebase onto > 1 branch",
+                       item->string);
+               return 0;
+       }
+
+       printf("    %-*s ", show_info->width, item->string);
+       if (branch_info->rebase) {
+               printf("rebases onto remote %s\n", merge->items[0].string);
+               return 0;
+       } else if (show_info->any_rebase) {
+               printf(" merges with remote %s\n", merge->items[0].string);
+               also = "    and with remote";
+       } else {
+               printf("merges with remote %s\n", merge->items[0].string);
+               also = "   and with remote";
+       }
+       for (i = 1; i < merge->nr; i++)
+               printf("    %-*s %s %s\n", show_info->width, "", also,
+                      merge->items[i].string);
+
+       return 0;
+}
 
+int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)
+{
+       struct show_info *show_info = cb_data;
+       struct push_info *push_info = push_item->util;
+       struct string_list_item *item;
+       int n;
+       if ((n = strlen(push_item->string)) > show_info->width)
+               show_info->width = n;
+       if ((n = strlen(push_info->dest)) > show_info->width2)
+               show_info->width2 = n;
+       item = string_list_append(push_item->string, show_info->list);
+       item->util = push_item->util;
+       return 0;
+}
+
+int show_push_info_item(struct string_list_item *item, void *cb_data)
+{
+       struct show_info *show_info = cb_data;
+       struct push_info *push_info = item->util;
+       char *src = item->string, *status = NULL;
+
+       switch (push_info->status) {
+       case PUSH_STATUS_CREATE:
+               status = "create";
+               break;
+       case PUSH_STATUS_DELETE:
+               status = "delete";
+               src = "(none)";
+               break;
+       case PUSH_STATUS_UPTODATE:
+               status = "up to date";
+               break;
+       case PUSH_STATUS_FASTFORWARD:
+               status = "fast forwardable";
+               break;
+       case PUSH_STATUS_OUTOFDATE:
+               status = "local out of date";
+               break;
+       case PUSH_STATUS_NOTQUERIED:
+               break;
+       }
+       if (status)
+               printf("    %-*s %s to %-*s (%s)\n", show_info->width, src,
+                       push_info->forced ? "forces" : "pushes",
+                       show_info->width2, push_info->dest, status);
+       else
+               printf("    %-*s %s to %s\n", show_info->width, src,
+                       push_info->forced ? "forces" : "pushes",
+                       push_info->dest);
        return 0;
 }
 
 static int show(int argc, const char **argv)
 {
-       int no_query = 0, result = 0;
+       int no_query = 0, result = 0, query_flag = 0;
        struct option options[] = {
                OPT_GROUP("show specific options"),
                OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
                OPT_END()
        };
        struct ref_states states;
+       struct string_list info_list = { NULL, 0, 0, 0 };
+       struct show_info info;
 
        argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
 
        if (argc < 1)
                return show_all();
 
+       if (!no_query)
+               query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);
+
        memset(&states, 0, sizeof(states));
+       memset(&info, 0, sizeof(info));
+       info.states = &states;
+       info.list = &info_list;
        for (; argc; argc--, argv++) {
                int i;
 
-               get_remote_ref_states(*argv, &states, !no_query);
+               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)");
-
-               for (i = 0; i < branch_list.nr; i++) {
-                       struct string_list_item *branch = branch_list.items + i;
-                       struct branch_info *info = branch->util;
-                       int j;
-
-                       if (!info->merge.nr || strcmp(*argv, info->remote))
-                               continue;
-                       printf("  Remote branch%s merged with 'git pull' "
-                               "while on branch %s\n   ",
-                               info->merge.nr > 1 ? "es" : "",
-                               branch->string);
-                       for (j = 0; j < info->merge.nr; j++)
-                               printf(" %s", info->merge.items[j].string);
-                       printf("\n");
+               if (no_query)
+                       printf("  HEAD branch: (not queried)\n");
+               else if (!states.heads.nr)
+                       printf("  HEAD branch: (unknown)\n");
+               else if (states.heads.nr == 1)
+                       printf("  HEAD branch: %s\n", states.heads.items[0].string);
+               else {
+                       printf("  HEAD branch (remote HEAD is ambiguous,"
+                              " may be one of the following):\n");
+                       for (i = 0; i < states.heads.nr; i++)
+                               printf("    %s\n", states.heads.items[i].string);
                }
 
-               if (!no_query) {
-                       show_list("  New remote branch%s (next fetch "
-                               "will store in remotes/%s)",
-                               &states.new, states.remote->name);
-                       show_list("  Stale tracking branch%s (use 'git remote "
-                               "prune')", &states.stale, "");
-               }
+               /* remote branch info */
+               info.width = 0;
+               for_each_string_list(add_remote_to_show_info, &states.new, &info);
+               for_each_string_list(add_remote_to_show_info, &states.tracked, &info);
+               for_each_string_list(add_remote_to_show_info, &states.stale, &info);
+               if (info.list->nr)
+                       printf("  Remote branch%s:%s\n",
+                              info.list->nr > 1 ? "es" : "",
+                               no_query ? " (status not queried)" : "");
+               for_each_string_list(show_remote_info_item, info.list, &info);
+               string_list_clear(info.list, 0);
+
+               /* git pull info */
+               info.width = 0;
+               info.any_rebase = 0;
+               for_each_string_list(add_local_to_show_info, &branch_list, &info);
+               if (info.list->nr)
+                       printf("  Local branch%s configured for 'git pull':\n",
+                              info.list->nr > 1 ? "es" : "");
+               for_each_string_list(show_local_info_item, info.list, &info);
+               string_list_clear(info.list, 0);
+
+               /* git push info */
+               if (states.remote->mirror)
+                       printf("  Local refs will be mirrored by 'git push'\n");
+
+               info.width = info.width2 = 0;
+               for_each_string_list(add_push_to_show_info, &states.push, &info);
+               sort_string_list(info.list);
+               if (info.list->nr)
+                       printf("  Local ref%s configured for 'git push'%s:\n",
+                               info.list->nr > 1 ? "s" : "",
+                               no_query ? " (status not queried)" : "");
+               for_each_string_list(show_push_info_item, info.list, &info);
+               string_list_clear(info.list, 0);
+
+               free_remote_ref_states(&states);
+       }
 
-               if (no_query)
-                       for_each_ref(append_ref_to_tracked_list, &states);
-               show_list("  Tracked remote branch%s", &states.tracked, "");
-
-               if (states.remote->push_refspec_nr) {
-                       printf("  Local branch%s pushed with 'git push'\n",
-                               states.remote->push_refspec_nr > 1 ?
-                                       "es" : "");
-                       for (i = 0; i < states.remote->push_refspec_nr; i++) {
-                               struct refspec *spec = states.remote->push + i;
-                               printf("    %s%s%s%s\n",
-                                      spec->force ? "+" : "",
-                                      abbrev_branch(spec->src),
-                                      spec->dst ? ":" : "",
-                                      spec->dst ? abbrev_branch(spec->dst) : "");
-                       }
-               }
+       return result;
+}
 
-               /* NEEDSWORK: free remote */
-               string_list_clear(&states.new, 0);
-               string_list_clear(&states.stale, 0);
-               string_list_clear(&states.tracked, 0);
+static int set_head(int argc, const char **argv)
+{
+       int i, opt_a = 0, opt_d = 0, result = 0;
+       struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
+       char *head_name = NULL;
+
+       struct option options[] = {
+               OPT_GROUP("set-head specific options"),
+               OPT_BOOLEAN('a', "auto", &opt_a,
+                           "set refs/remotes/<name>/HEAD according to remote"),
+               OPT_BOOLEAN('d', "delete", &opt_d,
+                           "delete refs/remotes/<name>/HEAD"),
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
+       if (argc)
+               strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
+
+       if (!opt_a && !opt_d && argc == 2) {
+               head_name = xstrdup(argv[1]);
+       } else if (opt_a && !opt_d && argc == 1) {
+               struct ref_states states;
+               memset(&states, 0, sizeof(states));
+               get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
+               if (!states.heads.nr)
+                       result |= error("Cannot determine remote HEAD");
+               else if (states.heads.nr > 1) {
+                       result |= error("Multiple remote HEAD branches. "
+                                       "Please choose one explicitly with:");
+                       for (i = 0; i < states.heads.nr; i++)
+                               fprintf(stderr, "  git remote set-head %s %s\n",
+                                       argv[0], states.heads.items[i].string);
+               } else
+                       head_name = xstrdup(states.heads.items[0].string);
+               free_remote_ref_states(&states);
+       } else if (opt_d && !opt_a && argc == 1) {
+               if (delete_ref(buf.buf, NULL, REF_NODEREF))
+                       result |= error("Could not delete %s", buf.buf);
+       } else
+               usage_with_options(builtin_remote_usage, options);
+
+       if (head_name) {
+               unsigned char sha1[20];
+               strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
+               /* make sure it's valid */
+               if (!resolve_ref(buf2.buf, sha1, 1, NULL))
+                       result |= error("Not a valid ref: %s", buf2.buf);
+               else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
+                       result |= error("Could not setup %s", buf.buf);
+               if (opt_a)
+                       printf("%s/HEAD set to %s\n", argv[0], head_name);
+               free(head_name);
        }
 
+       strbuf_release(&buf);
+       strbuf_release(&buf2);
        return result;
 }
 
@@ -770,7 +1129,7 @@ static int prune(int argc, const char **argv)
        for (; argc; argc--, argv++) {
                int i;
 
-               get_remote_ref_states(*argv, &states, 1);
+               get_remote_ref_states(*argv, &states, GET_REF_STATES);
 
                if (states.stale.nr) {
                        printf("Pruning %s\n", *argv);
@@ -791,10 +1150,7 @@ static int prune(int argc, const char **argv)
                        warn_dangling_symref(dangling_msg, refname);
                }
 
-               /* NEEDSWORK: free remote */
-               string_list_clear(&states.new, 0);
-               string_list_clear(&states.stale, 0);
-               string_list_clear(&states.tracked, 0);
+               free_remote_ref_states(&states);
        }
 
        return result;
@@ -919,6 +1275,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
                result = mv(argc, argv);
        else if (!strcmp(argv[0], "rm"))
                result = rm(argc, argv);
+       else if (!strcmp(argv[0], "set-head"))
+               result = set_head(argc, argv);
        else if (!strcmp(argv[0], "show"))
                result = show(argc, argv);
        else if (!strcmp(argv[0], "prune"))
index d65d01969252332eeee12b0419e4ba3a806952b1..9072905f10cbbb0f8297bc1b1c7dfb12613c80a7 100644 (file)
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "commit.h"
-#include "tag.h"
 #include "refs.h"
 #include "pkt-line.h"
 #include "run-command.h"
@@ -84,82 +83,8 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
        return 0;
 }
 
-static void unmark_and_free(struct commit_list *list, unsigned int mark)
-{
-       while (list) {
-               struct commit_list *temp = list;
-               temp->item->object.flags &= ~mark;
-               list = temp->next;
-               free(temp);
-       }
-}
-
-static int ref_newer(const unsigned char *new_sha1,
-                    const unsigned char *old_sha1)
-{
-       struct object *o;
-       struct commit *old, *new;
-       struct commit_list *list, *used;
-       int found = 0;
-
-       /* Both new and old must be commit-ish and new is descendant of
-        * old.  Otherwise we require --force.
-        */
-       o = deref_tag(parse_object(old_sha1), NULL, 0);
-       if (!o || o->type != OBJ_COMMIT)
-               return 0;
-       old = (struct commit *) o;
-
-       o = deref_tag(parse_object(new_sha1), NULL, 0);
-       if (!o || o->type != OBJ_COMMIT)
-               return 0;
-       new = (struct commit *) o;
-
-       if (parse_commit(new) < 0)
-               return 0;
-
-       used = list = NULL;
-       commit_list_insert(new, &list);
-       while (list) {
-               new = pop_most_recent_commit(&list, 1);
-               commit_list_insert(new, &used);
-               if (new == old) {
-                       found = 1;
-                       break;
-               }
-       }
-       unmark_and_free(list, 1);
-       unmark_and_free(used, 1);
-       return found;
-}
-
-static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct ref *ref;
-       int len;
-
-       /* we already know it starts with refs/ to get here */
-       if (check_ref_format(refname + 5))
-               return 0;
-
-       len = strlen(refname) + 1;
-       ref = xcalloc(1, sizeof(*ref) + len);
-       hashcpy(ref->new_sha1, sha1);
-       memcpy(ref->name, refname, len);
-       *local_tail = ref;
-       local_tail = &ref->next;
-       return 0;
-}
-
-static void get_local_heads(void)
-{
-       local_tail = &local_refs;
-       for_each_ref(one_local_ref, NULL);
-}
-
 static int receive_status(int in, struct ref *refs)
 {
        struct ref *hint;
@@ -387,7 +312,7 @@ static int refs_pushed(struct ref *ref)
 
 static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec)
 {
-       struct ref *ref;
+       struct ref *ref, *local_refs;
        int new_refs;
        int ask_for_status_report = 0;
        int allow_deleting_refs = 0;
@@ -405,7 +330,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
        /* No funny business with the matcher */
        remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
                                       &extra_have);
-       get_local_heads();
+       local_refs = get_local_heads();
 
        /* Does the other end support the reporting? */
        if (server_supports("report-status"))
index badd9120388569c79b137f679505b495cc1dbbe9..b28091b4455db15e80841f2779ce0686d4f18826 100644 (file)
@@ -101,7 +101,6 @@ static void insert_one_record(struct shortlog *log,
        }
        while (*oneline && isspace(*oneline) && *oneline != '\n')
                oneline++;
-       len = eol - oneline;
        format_subject(&subject, oneline, " ");
        buffer = strbuf_detach(&subject, NULL);
 
index dd43d5bef425af318a884bfc235a4aff40931633..1fde893cfa9f6318ae1e9958b2f61159b01c7c6a 100644 (file)
@@ -195,7 +195,7 @@ static int process_path(const char *path)
        struct stat st;
 
        len = strlen(path);
-       if (has_symlink_leading_path(len, path))
+       if (has_symlink_leading_path(path, len))
                return error("'%s' is beyond a symbolic link", path);
 
        /*
diff --git a/cache.h b/cache.h
index fdc4ada43a24fd64b93dc63589d13da911c70508..39789ee94a2f2e7dd1600115f4033ccf0e52c07b 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -140,8 +140,8 @@ struct ondisk_cache_entry_extended {
 };
 
 struct cache_entry {
-       unsigned int ce_ctime;
-       unsigned int ce_mtime;
+       struct cache_time ce_ctime;
+       struct cache_time ce_mtime;
        unsigned int ce_dev;
        unsigned int ce_ino;
        unsigned int ce_mode;
@@ -282,7 +282,7 @@ struct index_state {
        struct cache_entry **cache;
        unsigned int cache_nr, cache_alloc, cache_changed;
        struct cache_tree *cache_tree;
-       time_t timestamp;
+       struct cache_time timestamp;
        void *alloc;
        unsigned name_hash_initialized : 1,
                 initialized : 1;
@@ -428,7 +428,7 @@ extern int read_index_preload(struct index_state *, const char **pathspec);
 extern int read_index_from(struct index_state *, const char *path);
 extern int is_index_unborn(struct index_state *);
 extern int read_index_unmerged(struct index_state *);
-extern int write_index(const struct index_state *, int newfd);
+extern int write_index(struct index_state *, int newfd);
 extern int discard_index(struct index_state *);
 extern int unmerged_index(const struct index_state *);
 extern int verify_path(const char *path);
@@ -443,6 +443,7 @@ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int opt
 extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
 extern int remove_index_entry_at(struct index_state *, int pos);
+extern void remove_marked_cache_entries(struct index_state *istate);
 extern int remove_file_from_index(struct index_state *, const char *path);
 #define ADD_CACHE_VERBOSE 1
 #define ADD_CACHE_PRETEND 2
@@ -725,11 +726,13 @@ struct checkout {
 };
 
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
-extern int has_symlink_leading_path(int len, const char *name);
-extern int has_symlink_or_noent_leading_path(int len, const char *name);
-extern int has_dirs_only_path(int len, const char *name, int prefix_len);
-extern void invalidate_lstat_cache(int len, const char *name);
+extern int has_symlink_leading_path(const char *name, int len);
+extern int has_symlink_or_noent_leading_path(const char *name, int len);
+extern int has_dirs_only_path(const char *name, int len, int prefix_len);
+extern void invalidate_lstat_cache(const char *name, int len);
 extern void clear_lstat_cache(void);
+extern void schedule_dir_for_removal(const char *name, int len);
+extern void remove_scheduled_dirs(void);
 
 extern struct alternate_object_database {
        struct alternate_object_database *next;
@@ -802,7 +805,7 @@ struct ref {
 #define REF_HEADS      (1u << 1)
 #define REF_TAGS       (1u << 2)
 
-extern struct ref *find_ref_by_name(struct ref *list, const char *name);
+extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
 
 #define CONNECT_VERBOSE       (1u << 0)
 extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
index b3b86aebcb81972ca50a031f4e15bb7a905101e0..066ce841ed76e03dd87e789f6688cc3f5411ba64 100644 (file)
@@ -712,9 +712,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        result_size = buf.len;
                        result = strbuf_detach(&buf, NULL);
                        elem->mode = canon_mode(st.st_mode);
-               }
-               else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
-                        !fstat(fd, &st)) {
+               } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
                        size_t len = xsize_t(st.st_size);
                        ssize_t done;
                        int is_file, i;
index 27bcf3fd6b481eb058b357241da320a02e3d4096..171fa85e4ae9fa026bbb72e2e8b8b098d2ba22ed 100644 (file)
@@ -4,6 +4,119 @@
 
 unsigned int _CRT_fmode = _O_BINARY;
 
+static int err_win_to_posix(DWORD winerr)
+{
+       int error = ENOSYS;
+       switch(winerr) {
+       case ERROR_ACCESS_DENIED: error = EACCES; break;
+       case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
+       case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
+       case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
+       case ERROR_ALREADY_EXISTS: error = EEXIST; break;
+       case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
+       case ERROR_BAD_COMMAND: error = EIO; break;
+       case ERROR_BAD_DEVICE: error = ENODEV; break;
+       case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
+       case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
+       case ERROR_BAD_FORMAT: error = ENOEXEC; break;
+       case ERROR_BAD_LENGTH: error = EINVAL; break;
+       case ERROR_BAD_PATHNAME: error = ENOENT; break;
+       case ERROR_BAD_PIPE: error = EPIPE; break;
+       case ERROR_BAD_UNIT: error = ENODEV; break;
+       case ERROR_BAD_USERNAME: error = EINVAL; break;
+       case ERROR_BROKEN_PIPE: error = EPIPE; break;
+       case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
+       case ERROR_BUSY: error = EBUSY; break;
+       case ERROR_BUSY_DRIVE: error = EBUSY; break;
+       case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
+       case ERROR_CANNOT_MAKE: error = EACCES; break;
+       case ERROR_CANTOPEN: error = EIO; break;
+       case ERROR_CANTREAD: error = EIO; break;
+       case ERROR_CANTWRITE: error = EIO; break;
+       case ERROR_CRC: error = EIO; break;
+       case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
+       case ERROR_DEVICE_IN_USE: error = EBUSY; break;
+       case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
+       case ERROR_DIRECTORY: error = EINVAL; break;
+       case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
+       case ERROR_DISK_CHANGE: error = EIO; break;
+       case ERROR_DISK_FULL: error = ENOSPC; break;
+       case ERROR_DRIVE_LOCKED: error = EBUSY; break;
+       case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
+       case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
+       case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
+       case ERROR_FILE_EXISTS: error = EEXIST; break;
+       case ERROR_FILE_INVALID: error = ENODEV; break;
+       case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
+       case ERROR_GEN_FAILURE: error = EIO; break;
+       case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
+       case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
+       case ERROR_INVALID_ACCESS: error = EACCES; break;
+       case ERROR_INVALID_ADDRESS: error = EFAULT; break;
+       case ERROR_INVALID_BLOCK: error = EFAULT; break;
+       case ERROR_INVALID_DATA: error = EINVAL; break;
+       case ERROR_INVALID_DRIVE: error = ENODEV; break;
+       case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
+       case ERROR_INVALID_FLAGS: error = EINVAL; break;
+       case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
+       case ERROR_INVALID_HANDLE: error = EBADF; break;
+       case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
+       case ERROR_INVALID_NAME: error = EINVAL; break;
+       case ERROR_INVALID_OWNER: error = EINVAL; break;
+       case ERROR_INVALID_PARAMETER: error = EINVAL; break;
+       case ERROR_INVALID_PASSWORD: error = EPERM; break;
+       case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
+       case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
+       case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
+       case ERROR_INVALID_WORKSTATION: error = EACCES; break;
+       case ERROR_IO_DEVICE: error = EIO; break;
+       case ERROR_IO_INCOMPLETE: error = EINTR; break;
+       case ERROR_LOCKED: error = EBUSY; break;
+       case ERROR_LOCK_VIOLATION: error = EACCES; break;
+       case ERROR_LOGON_FAILURE: error = EACCES; break;
+       case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
+       case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
+       case ERROR_MORE_DATA: error = EPIPE; break;
+       case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
+       case ERROR_NOACCESS: error = EFAULT; break;
+       case ERROR_NONE_MAPPED: error = EINVAL; break;
+       case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
+       case ERROR_NOT_READY: error = EAGAIN; break;
+       case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
+       case ERROR_NO_DATA: error = EPIPE; break;
+       case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
+       case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
+       case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
+       case ERROR_OPEN_FAILED: error = EIO; break;
+       case ERROR_OPEN_FILES: error = EBUSY; break;
+       case ERROR_OPERATION_ABORTED: error = EINTR; break;
+       case ERROR_OUTOFMEMORY: error = ENOMEM; break;
+       case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
+       case ERROR_PATH_BUSY: error = EBUSY; break;
+       case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
+       case ERROR_PIPE_BUSY: error = EBUSY; break;
+       case ERROR_PIPE_CONNECTED: error = EPIPE; break;
+       case ERROR_PIPE_LISTENING: error = EPIPE; break;
+       case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
+       case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
+       case ERROR_READ_FAULT: error = EIO; break;
+       case ERROR_SEEK: error = EIO; break;
+       case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
+       case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
+       case ERROR_SHARING_VIOLATION: error = EACCES; break;
+       case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
+       case ERROR_SWAPERROR: error = ENOENT; break;
+       case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
+       case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
+       case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
+       case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
+       case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
+       case ERROR_WRITE_FAULT: error = EIO; break;
+       case ERROR_WRITE_PROTECT: error = EROFS; break;
+       }
+       return error;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -1005,3 +1118,24 @@ void mingw_open_html(const char *unixpath)
        printf("Launching default browser to display HTML ...\n");
        ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
 }
+
+int link(const char *oldpath, const char *newpath)
+{
+       typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+       static T create_hard_link = NULL;
+       if (!create_hard_link) {
+               create_hard_link = (T) GetProcAddress(
+                       GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+               if (!create_hard_link)
+                       create_hard_link = (T)-1;
+       }
+       if (create_hard_link == (T)-1) {
+               errno = ENOSYS;
+               return -1;
+       }
+       if (!create_hard_link(newpath, oldpath, NULL)) {
+               errno = err_win_to_posix(GetLastError());
+               return -1;
+       }
+       return 0;
+}
index 6e246864429e276f116761e64bf89eb6e036fc28..762eb143a7654480d8831a6258a0767c0f33900b 100644 (file)
@@ -67,8 +67,6 @@ static inline int readlink(const char *path, char *buf, size_t bufsiz)
 { errno = ENOSYS; return -1; }
 static inline int symlink(const char *oldpath, const char *newpath)
 { errno = ENOSYS; return -1; }
-static inline int link(const char *oldpath, const char *newpath)
-{ errno = ENOSYS; return -1; }
 static inline int fchmod(int fildes, mode_t mode)
 { errno = ENOSYS; return -1; }
 static inline int fork(void)
@@ -134,6 +132,7 @@ int getpagesize(void);      /* defined in MinGW's libgcc.a */
 struct passwd *getpwuid(int uid);
 int setitimer(int type, struct itimerval *in, struct itimerval *out);
 int sigaction(int sig, struct sigaction *in, struct sigaction *out);
+int link(const char *oldpath, const char *newpath);
 
 /*
  * replacements of existing functions
@@ -160,6 +159,11 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
 int mingw_rename(const char*, const char*);
 #define rename mingw_rename
 
+#ifdef USE_WIN32_MMAP
+int mingw_getpagesize(void);
+#define getpagesize mingw_getpagesize
+#endif
+
 /* Use mingw_lstat() instead of lstat()/stat() and
  * mingw_fstat() instead of fstat() on Windows.
  */
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
new file mode 100644 (file)
index 0000000..779d796
--- /dev/null
@@ -0,0 +1,53 @@
+#include "../git-compat-util.h"
+
+/*
+ * Note that this doesn't return the actual pagesize, but
+ * the allocation granularity. If future Windows specific git code
+ * needs the real getpagesize function, we need to find another solution.
+ */
+int mingw_getpagesize(void)
+{
+       SYSTEM_INFO si;
+       GetSystemInfo(&si);
+       return si.dwAllocationGranularity;
+}
+
+void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+       HANDLE hmap;
+       void *temp;
+       size_t len;
+       struct stat st;
+       uint64_t o = offset;
+       uint32_t l = o & 0xFFFFFFFF;
+       uint32_t h = (o >> 32) & 0xFFFFFFFF;
+
+       if (!fstat(fd, &st))
+               len = xsize_t(st.st_size);
+       else
+               die("mmap: could not determine filesize");
+
+       if ((length + offset) > len)
+               length = len - offset;
+
+       if (!(flags & MAP_PRIVATE))
+               die("Invalid usage of mmap when built with USE_WIN32_MMAP");
+
+       hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY,
+               0, 0, 0);
+
+       if (!hmap)
+               return MAP_FAILED;
+
+       temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start);
+
+       if (!CloseHandle(hmap))
+               warning("unable to close file mapping handle\n");
+
+       return temp ? temp : MAP_FAILED;
+}
+
+int git_munmap(void *start, size_t length)
+{
+       return !UnmapViewOfFile(start);
+}
index e2d96dfe6f75213de567174261d9aeba3e663d9d..44dc293ad314379d7835d9d96a5c3fd12ad2b27f 100644 (file)
@@ -18,8 +18,6 @@
 
  This file is git-specific. Therefore, this file does not attempt
  to implement any codes that are not used by git.
-
- TODO: K
 */
 
 static HANDLE console;
@@ -79,6 +77,20 @@ static void set_console_attr(void)
        SetConsoleTextAttribute(console, attributes);
 }
 
+static void erase_in_line(void)
+{
+       CONSOLE_SCREEN_BUFFER_INFO sbi;
+
+       if (!console)
+               return;
+
+       GetConsoleScreenBufferInfo(console, &sbi);
+       FillConsoleOutputCharacterA(console, ' ',
+               sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
+               NULL);
+}
+
+
 static const char *set_attr(const char *str)
 {
        const char *func;
@@ -218,7 +230,7 @@ static const char *set_attr(const char *str)
                set_console_attr();
                break;
        case 'K':
-               /* TODO */
+               erase_in_line();
                break;
        default:
                /* Unsupported code */
index 0c8c76f13b03028ad400b1c5b72b3cf0a7ec0940..50efd639c4d68af1428a8a45606ae4897a8d2dd9 100644 (file)
--- a/config.c
+++ b/config.c
@@ -644,28 +644,37 @@ int git_config_global(void)
 
 int git_config(config_fn_t fn, void *data)
 {
-       int ret = 0;
+       int ret = 0, found = 0;
        char *repo_config = NULL;
        const char *home = NULL;
 
        /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
        if (config_exclusive_filename)
                return git_config_from_file(fn, config_exclusive_filename, data);
-       if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
+       if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
+               found += 1;
+       }
 
        home = getenv("HOME");
        if (git_config_global() && home) {
                char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
-               if (!access(user_config, R_OK))
+               if (!access(user_config, R_OK)) {
                        ret += git_config_from_file(fn, user_config, data);
+                       found += 1;
+               }
                free(user_config);
        }
 
        repo_config = git_pathdup("config");
-       ret += git_config_from_file(fn, repo_config, data);
+       if (!access(repo_config, R_OK)) {
+               ret += git_config_from_file(fn, repo_config, data);
+               found += 1;
+       }
        free(repo_config);
+       if (found == 0)
+               return -1;
        return ret;
 }
 
index 0a35cc1b25c22256845acffb35828cfa44316892..7636bf976e78a6622281501af2dcc0135781f60a 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -504,7 +504,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
                                  const char *prog, int flags)
 {
        char *url = xstrdup(url_orig);
-       char *host, *path = url;
+       char *host, *path;
        char *end;
        int c;
        struct child_process *conn;
index 271b911f7a1300057c0b100c1bdfe5d68a0e3248..ed235f759645c0f657d47b3f0d73a3bcfbf6b1d6 100755 (executable)
@@ -1516,7 +1516,7 @@ _git_config ()
 
 _git_remote ()
 {
-       local subcommands="add rename rm show prune update"
+       local subcommands="add rename rm show prune update set-head"
        local subcommand="$(__git_find_subcommand "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
index 0cda3d2eeae3054d1835676d198e3aae01288259..0deda3a0e41511bb1b71d30d335b4909e8719169 100755 (executable)
@@ -4,7 +4,7 @@
 # This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
 # git-difftool-helper script.  This script exports
 # GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
-# GIT_DIFFTOOL_NO_PROMPT and GIT_MERGE_TOOL for use by git-difftool-helper.
+# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper.
 # Any arguments that are unknown to this script are forwarded to 'git diff'.
 
 use strict;
@@ -49,12 +49,12 @@ sub generate_command
                }
                if ($arg eq '-t' or $arg eq '--tool') {
                        usage() if $#ARGV <= $idx;
-                       $ENV{GIT_MERGE_TOOL} = $ARGV[$idx + 1];
+                       $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
                        $skip_next = 1;
                        next;
                }
                if ($arg =~ /^--tool=/) {
-                       $ENV{GIT_MERGE_TOOL} = substr($arg, 7);
+                       $ENV{GIT_DIFF_TOOL} = substr($arg, 7);
                        next;
                }
                if ($arg eq '--no-prompt') {
index db3af6a833f030cae94dbcd5926aac1b380969a7..9c0a13452a60059b504f07cb94a3cc16e1a2e6e7 100755 (executable)
@@ -128,8 +128,10 @@ launch_merge_tool () {
        cleanup_temp_files
 }
 
-# Verifies that mergetool.<tool>.cmd exists
+# Verifies that (difftool|mergetool).<tool>.cmd exists
 valid_custom_tool() {
+       merge_tool_cmd="$(git config difftool.$1.cmd)"
+       test -z "$merge_tool_cmd" &&
        merge_tool_cmd="$(git config mergetool.$1.cmd)"
        test -n "$merge_tool_cmd"
 }
@@ -150,8 +152,11 @@ valid_tool() {
 }
 
 # Sets up the merge_tool_path variable.
-# This handles the mergetool.<tool>.path configuration.
+# This handles the difftool.<tool>.path configuration.
+# This also falls back to mergetool defaults.
 init_merge_tool_path() {
+       merge_tool_path=$(git config difftool."$1".path)
+       test -z "$merge_tool_path" &&
        merge_tool_path=$(git config mergetool."$1".path)
        if test -z "$merge_tool_path"; then
                case "$1" in
@@ -165,15 +170,19 @@ init_merge_tool_path() {
        fi
 }
 
-# Allow the GIT_MERGE_TOOL variable to provide a default value
+# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
 test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
+test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
 
-# If not merge tool was specified then use the merge.tool
+# If merge tool was not specified then use the diff.tool
 # configuration variable.  If that's invalid then reset merge_tool.
+# Fallback to merge.tool.
 if test -z "$merge_tool"; then
+       merge_tool=$(git config diff.tool)
+       test -z "$merge_tool" &&
        merge_tool=$(git config merge.tool)
        if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
-               echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
+               echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
                echo >&2 "Resetting to default..."
                unset merge_tool
        fi
index 6e2610cda6d2721eb4fb9ac063bb47ef80bfbae3..2b7bc03ec3f63ce8bfe4ba8c00af9ab807e6cedf 100644 (file)
@@ -32,23 +32,23 @@ OPTIONS
        vimdiff, gvimdiff, ecmerge, and opendiff
 +
 If a merge resolution program is not specified, 'git-difftool'
-will use the configuration variable `merge.tool`.  If the
-configuration variable `merge.tool` is not set, 'git difftool'
+will use the configuration variable `diff.tool`.  If the
+configuration variable `diff.tool` is not set, 'git-difftool'
 will pick a suitable default.
 +
 You can explicitly provide a full path to the tool by setting the
-configuration variable `mergetool.<tool>.path`. For example, you
+configuration variable `difftool.<tool>.path`. For example, you
 can configure the absolute path to kdiff3 by setting
-`mergetool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
+`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
 tool is available in PATH.
 +
 Instead of running one of the known merge tool programs,
 'git-difftool' can be customized to run an alternative program
 by specifying the command line to invoke in a configuration
-variable `mergetool.<tool>.cmd`.
+variable `difftool.<tool>.cmd`.
 +
 When 'git-difftool' is invoked with this tool (either through the
-`-t` or `--tool` option or the `merge.tool` configuration variable)
+`-t` or `--tool` option or the `diff.tool` configuration variable)
 the configured command line will be invoked with the following
 variables available: `$LOCAL` is set to the name of the temporary
 file containing the contents of the diff pre-image and `$REMOTE`
@@ -61,24 +61,24 @@ with custom merge tool commands and has the same value as `$LOCAL`.
 
 CONFIG VARIABLES
 ----------------
-merge.tool::
-       The default merge tool to use.
-+
-See the `--tool=<tool>` option above for more details.
+'git-difftool' falls back to 'git-mergetool' config variables when the
+difftool equivalents have not been defined.
 
-merge.keepBackup::
-       The original, unedited file content can be saved to a file with
-       a `.orig` extension.  Defaults to `true` (i.e. keep the backup files).
+diff.tool::
+       The default merge tool to use.
 
-mergetool.<tool>.path::
+difftool.<tool>.path::
        Override the path for the given tool.  This is useful in case
        your tool is not in the PATH.
 
-mergetool.<tool>.cmd::
+difftool.<tool>.cmd::
        Specify the command to invoke the specified merge tool.
 +
 See the `--tool=<tool>` option above for more details.
 
+merge.keepBackup::
+       The original, unedited file content can be saved to a file with
+       a `.orig` extension.  Defaults to `true` (i.e. keep the backup files).
 
 SEE ALSO
 --------
index 23aeb257b9557cb146586868084ce1b20d7e7ac8..6309d146e74a428520d09cbff4dc8d9a429ec001 100755 (executable)
 
 my $branch_name = 'import-tars';
 my $branch_ref = "refs/heads/$branch_name";
-my $committer_name = 'T Ar Creator';
-my $committer_email = 'tar@example.com';
+my $author_name = $ENV{'GIT_AUTHOR_NAME'} || 'T Ar Creator';
+my $author_email = $ENV{'GIT_AUTHOR_EMAIL'} || 'tar@example.com';
+my $committer_name = $ENV{'GIT_COMMITTER_NAME'} || `git config --get user.name`;
+my $committer_email = $ENV{'GIT_COMMITTER_EMAIL'} || `git config --get user.email`;
+
+chomp($committer_name, $committer_email);
 
 open(FI, '|-', 'git', 'fast-import', '--quiet')
        or die "Unable to start git fast-import: $!\n";
 foreach my $tar_file (@ARGV)
 {
+       my $commit_time = time;
        $tar_file =~ m,([^/]+)$,;
        my $tar_name = $1;
 
@@ -39,7 +44,7 @@
                die "Unrecognized compression format: $tar_file\n";
        }
 
-       my $commit_time = 0;
+       my $author_time = 0;
        my $next_mark = 1;
        my $have_top_dir = 1;
        my ($top_dir, %files);
@@ -92,7 +97,7 @@
                }
                $files{$path} = [$next_mark++, $mode];
 
-               $commit_time = $mtime if $mtime > $commit_time;
+               $author_time = $mtime if $mtime > $author_time;
                $path =~ m,^([^/]+)/,;
                $top_dir = $1 unless $top_dir;
                $have_top_dir = 0 if $top_dir ne $1;
 
        print FI <<EOF;
 commit $branch_ref
+author $author_name <$author_email> $author_time +0000
 committer $committer_name <$committer_email> $commit_time +0000
 data <<END_OF_COMMIT_MESSAGE
 Imported from $tar_file.
        print FI <<EOF;
 tag $tar_name
 from $branch_ref
-tagger $committer_name <$committer_email> $commit_time +0000
+tagger $author_name <$author_email> $author_time +0000
 data <<END_OF_TAG_MESSAGE
 Package $tar_name
 END_OF_TAG_MESSAGE
index 79d06068344f5a602f6c8799f6671ccbf98cf49c..a310fb2ad08cfb5fac01f5519e8b95b2338b07db 100644 (file)
@@ -31,7 +31,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
                        return -1;
                return 1;
        }
-       if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+       if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
                return 1;
        if (S_ISDIR(st->st_mode)) {
                unsigned char sub[20];
index 574b3e833711fe3794636b86dbf2b9d9deb5e151..d0ef8397008824fb5139680856e3229ecf2c4eb1 100644 (file)
@@ -25,10 +25,12 @@ static unsigned int contains(struct diff_filespec *one,
                regmatch_t regmatch;
                int flags = 0;
 
+               assert(data[sz] == '\0');
                while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
                        flags |= REG_NOTBOL;
-                       data += regmatch.rm_so;
-                       if (*data) data++;
+                       data += regmatch.rm_eo;
+                       if (*data && regmatch.rm_so == regmatch.rm_eo)
+                               data++;
                        cnt++;
                }
 
diff --git a/dir.c b/dir.c
index 2245749b3fe74f793bd1997d2238883abe61fc07..371bcf7cfbc0b3ae7693fb129a6082924c84194d 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -720,7 +720,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
 {
        struct path_simplify *simplify;
 
-       if (has_symlink_leading_path(strlen(path), path))
+       if (has_symlink_leading_path(path, strlen(path)))
                return dir->nr;
 
        simplify = create_simplify(pathspec);
diff --git a/entry.c b/entry.c
index 05aa58d34823258789ec9e32abc897b8e6777412..5daacc2fe51eada819bedea05f958fbf87f5b889 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -2,15 +2,19 @@
 #include "blob.h"
 #include "dir.h"
 
-static void create_directories(const char *path, const struct checkout *state)
+static void create_directories(const char *path, int path_len,
+                              const struct checkout *state)
 {
-       int len = strlen(path);
-       char *buf = xmalloc(len + 1);
-       const char *slash = path;
-
-       while ((slash = strchr(slash+1, '/')) != NULL) {
-               len = slash - path;
-               memcpy(buf, path, len);
+       char *buf = xmalloc(path_len + 1);
+       int len = 0;
+
+       while (len < path_len) {
+               do {
+                       buf[len] = path[len];
+                       len++;
+               } while (len < path_len && path[len] != '/');
+               if (len >= path_len)
+                       break;
                buf[len] = 0;
 
                /*
@@ -20,7 +24,7 @@ static void create_directories(const char *path, const struct checkout *state)
                 * we test the path components of the prefix with the
                 * stat() function instead of the lstat() function.
                 */
-               if (has_dirs_only_path(len, buf, state->base_dir_len))
+               if (has_dirs_only_path(buf, len, state->base_dir_len))
                        continue; /* ok, it is already a directory. */
 
                /*
@@ -74,7 +78,7 @@ static int create_file(const char *path, unsigned int mode)
        return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
 }
 
-static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned long *size)
+static void *read_blob_entry(struct cache_entry *ce, unsigned long *size)
 {
        enum object_type type;
        void *new = read_sha1_file(ce->sha1, &type, size);
@@ -89,36 +93,52 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned
 
 static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
 {
-       int fd;
-       long wrote;
-
-       switch (ce->ce_mode & S_IFMT) {
-               char *new;
-               struct strbuf buf;
-               unsigned long size;
+       unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
+       int fd, ret, fstat_done = 0;
+       char *new;
+       struct strbuf buf = STRBUF_INIT;
+       unsigned long size;
+       size_t wrote, newsize = 0;
+       struct stat st;
 
+       switch (ce_mode_s_ifmt) {
        case S_IFREG:
-               new = read_blob_entry(ce, path, &size);
+       case S_IFLNK:
+               new = read_blob_entry(ce, &size);
                if (!new)
                        return error("git checkout-index: unable to read sha1 file of %s (%s)",
                                path, sha1_to_hex(ce->sha1));
 
+               if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
+                       ret = symlink(new, path);
+                       free(new);
+                       if (ret)
+                               return error("git checkout-index: unable to create symlink %s (%s)",
+                                            path, strerror(errno));
+                       break;
+               }
+
                /*
                 * Convert from git internal format to working tree format
                 */
-               strbuf_init(&buf, 0);
-               if (convert_to_working_tree(ce->name, new, size, &buf)) {
-                       size_t newsize = 0;
+               if (ce_mode_s_ifmt == S_IFREG &&
+                   convert_to_working_tree(ce->name, new, size, &buf)) {
                        free(new);
                        new = strbuf_detach(&buf, &newsize);
                        size = newsize;
                }
 
                if (to_tempfile) {
-                       strcpy(path, ".merge_file_XXXXXX");
+                       if (ce_mode_s_ifmt == S_IFREG)
+                               strcpy(path, ".merge_file_XXXXXX");
+                       else
+                               strcpy(path, ".merge_link_XXXXXX");
                        fd = mkstemp(path);
-               } else
+               } else if (ce_mode_s_ifmt == S_IFREG) {
                        fd = create_file(path, ce->ce_mode);
+               } else {
+                       fd = create_file(path, 0666);
+               }
                if (fd < 0) {
                        free(new);
                        return error("git checkout-index: unable to create file %s (%s)",
@@ -126,41 +146,16 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
                }
 
                wrote = write_in_full(fd, new, size);
+               /* use fstat() only when path == ce->name */
+               if (state->refresh_cache && !to_tempfile && !state->base_dir_len) {
+                       fstat(fd, &st);
+                       fstat_done = 1;
+               }
                close(fd);
                free(new);
                if (wrote != size)
                        return error("git checkout-index: unable to write file %s", path);
                break;
-       case S_IFLNK:
-               new = read_blob_entry(ce, path, &size);
-               if (!new)
-                       return error("git checkout-index: unable to read sha1 file of %s (%s)",
-                               path, sha1_to_hex(ce->sha1));
-               if (to_tempfile || !has_symlinks) {
-                       if (to_tempfile) {
-                               strcpy(path, ".merge_link_XXXXXX");
-                               fd = mkstemp(path);
-                       } else
-                               fd = create_file(path, 0666);
-                       if (fd < 0) {
-                               free(new);
-                               return error("git checkout-index: unable to create "
-                                                "file %s (%s)", path, strerror(errno));
-                       }
-                       wrote = write_in_full(fd, new, size);
-                       close(fd);
-                       free(new);
-                       if (wrote != size)
-                               return error("git checkout-index: unable to write file %s",
-                                       path);
-               } else {
-                       wrote = symlink(new, path);
-                       free(new);
-                       if (wrote)
-                               return error("git checkout-index: unable to create "
-                                                "symlink %s (%s)", path, strerror(errno));
-               }
-               break;
        case S_IFGITLINK:
                if (to_tempfile)
                        return error("git checkout-index: cannot create temporary subproject %s", path);
@@ -172,8 +167,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
        }
 
        if (state->refresh_cache) {
-               struct stat st;
-               lstat(ce->name, &st);
+               if (!fstat_done)
+                       lstat(ce->name, &st);
                fill_stat_cache_info(ce, &st);
        }
        return 0;
@@ -190,6 +185,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
 
        memcpy(path, state->base_dir, len);
        strcpy(path + len, ce->name);
+       len += ce_namelen(ce);
 
        if (!lstat(path, &st)) {
                unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
@@ -218,6 +214,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
                        return error("unable to unlink old '%s' (%s)", path, strerror(errno));
        } else if (state->not_new)
                return 0;
-       create_directories(path, state);
+       create_directories(path, len, state);
        return write_entry(ce, path, state, 0);
 }
index 878d83dd0863570042af80919899b4d6aa57e35b..f09f244061ab9be5905b69e701faef8f416fd53e 100644 (file)
@@ -166,7 +166,7 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
        return strncmp(str, prefix, len) ? NULL : str + len;
 }
 
-#ifdef NO_MMAP
+#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
 
 #ifndef PROT_READ
 #define PROT_READ 1
@@ -180,13 +180,19 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
 extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
 extern int git_munmap(void *start, size_t length);
 
+#else /* NO_MMAP || USE_WIN32_MMAP */
+
+#include <sys/mman.h>
+
+#endif /* NO_MMAP || USE_WIN32_MMAP */
+
+#ifdef NO_MMAP
+
 /* This value must be multiple of (pagesize * 2) */
 #define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
 
 #else /* NO_MMAP */
 
-#include <sys/mman.h>
-
 /* This value must be multiple of (pagesize * 2) */
 #define DEFAULT_PACKED_GIT_WINDOW_SIZE \
        (sizeof(void*) >= 8 \
@@ -388,4 +394,18 @@ void git_qsort(void *base, size_t nmemb, size_t size,
 # define FORCE_DIR_SET_GID 0
 #endif
 
+#ifdef NO_NSEC
+#undef USE_NSEC
+#define ST_CTIME_NSEC(st) 0
+#define ST_MTIME_NSEC(st) 0
+#else
+#ifdef USE_ST_TIMESPEC
+#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
+#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
+#else
+#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
+#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
+#endif
+#endif
+
 #endif
index 3dc659dd5896ce6c887eb786718919aef82f4ac6..314cd364b8f4df5e170dd0ffd9e874b3e6c2737c 100755 (executable)
@@ -442,6 +442,30 @@ do_rest () {
        done
 }
 
+# skip picking commits whose parents are unchanged
+skip_unnecessary_picks () {
+       fd=3
+       while read command sha1 rest
+       do
+               # fd=3 means we skip the command
+               case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in
+               3,pick,"$ONTO"*|3,p,"$ONTO"*)
+                       # pick a commit whose parent is current $ONTO -> skip
+                       ONTO=$sha1
+                       ;;
+               3,#*|3,,*)
+                       # copy comments
+                       ;;
+               *)
+                       fd=1
+                       ;;
+               esac
+               echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
+       done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
+       mv -f "$TODO".new "$TODO" ||
+       die "Could not skip unnecessary pick commands"
+}
+
 # check if no other options are set
 is_standalone () {
        test $# -eq 2 -a "$2" = '--' &&
@@ -746,6 +770,8 @@ EOF
                has_action "$TODO" ||
                        die_abort "Nothing to do"
 
+               test -d "$REWRITTEN" || skip_unnecessary_picks
+
                git update-ref ORIG_HEAD $HEAD
                output git checkout $ONTO && do_rest
                ;;
index d38ab0b83fd46e4b3f7c0e81bc97a4b313925786..0ade6992289a807a268ad887d8a71ba54a87cf49 100755 (executable)
@@ -309,6 +309,10 @@ do
                        ;;
                esac
                ;;
+       --committer-date-is-author-date|--ignore-date)
+               git_am_opt="$git_am_opt $1"
+               force_rebase=t
+               ;;
        -C*)
                git_am_opt="$git_am_opt $1"
                ;;
index 57127aa823833f75fb546e738fcb19381fc331f7..546d2ebc0c72d4a330b3b40ca886af9340afb5af 100755 (executable)
@@ -821,7 +821,7 @@ sub send_message
 Message-Id: $message_id
 X-Mailer: git-send-email $gitversion
 ";
-       if ($thread && $reply_to) {
+       if ($reply_to) {
 
                $header .= "In-Reply-To: $reply_to\n";
                $header .= "References: $references\n";
diff --git a/grep.c b/grep.c
index 062b2b6f28f6332518240d2a474a7739735e1ecf..f3a27d7d6e141bd8813b978edbe33d16aa764fb4 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -39,6 +39,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
 {
        int err;
 
+       p->word_regexp = opt->word_regexp;
+
        if (opt->fixed || is_fixed(p->pattern))
                p->fixed = 1;
        if (opt->regflags & REG_ICASE)
@@ -190,7 +192,8 @@ void compile_grep_patterns(struct grep_opt *opt)
         * A classic recursive descent parser would do.
         */
        p = opt->pattern_list;
-       opt->pattern_expression = compile_pattern_expr(&p);
+       if (p)
+               opt->pattern_expression = compile_pattern_expr(&p);
        if (p)
                die("incomplete pattern expression: %s", p->pattern);
 }
@@ -251,18 +254,6 @@ static int word_char(char ch)
        return isalnum(ch) || ch == '_';
 }
 
-static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
-                     const char *name, unsigned lno, char sign)
-{
-       if (opt->null_following_name)
-               sign = '\0';
-       if (opt->pathname)
-               printf("%s%c", name, sign);
-       if (opt->linenum)
-               printf("%d%c", lno, sign);
-       printf("%.*s\n", (int)(eol-bol), bol);
-}
-
 static void show_name(struct grep_opt *opt, const char *name)
 {
        printf("%s%c", name, opt->null_following_name ? '\0' : '\n');
@@ -306,11 +297,12 @@ static struct {
        { "committer ", 10 },
 };
 
-static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx)
+static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
+                            enum grep_context ctx,
+                            regmatch_t *pmatch, int eflags)
 {
        int hit = 0;
        int saved_ch = 0;
-       regmatch_t pmatch[10];
 
        if ((p->token != GREP_PATTERN) &&
            ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
@@ -329,16 +321,12 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
        }
 
  again:
-       if (!p->fixed) {
-               regex_t *exp = &p->regexp;
-               hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
-                              pmatch, 0);
-       }
-       else {
+       if (p->fixed)
                hit = !fixmatch(p->pattern, bol, pmatch);
-       }
+       else
+               hit = !regexec(&p->regexp, bol, 1, pmatch, eflags);
 
-       if (hit && opt->word_regexp) {
+       if (hit && p->word_regexp) {
                if ((pmatch[0].rm_so < 0) ||
                    (eol - bol) <= pmatch[0].rm_so ||
                    (pmatch[0].rm_eo < 0) ||
@@ -378,39 +366,33 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
        return hit;
 }
 
-static int match_expr_eval(struct grep_opt *o,
-                          struct grep_expr *x,
-                          char *bol, char *eol,
-                          enum grep_context ctx,
-                          int collect_hits)
+static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
+                          enum grep_context ctx, int collect_hits)
 {
        int h = 0;
+       regmatch_t match;
 
        switch (x->node) {
        case GREP_NODE_ATOM:
-               h = match_one_pattern(o, x->u.atom, bol, eol, ctx);
+               h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
                break;
        case GREP_NODE_NOT:
-               h = !match_expr_eval(o, x->u.unary, bol, eol, ctx, 0);
+               h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0);
                break;
        case GREP_NODE_AND:
-               if (!collect_hits)
-                       return (match_expr_eval(o, x->u.binary.left,
-                                               bol, eol, ctx, 0) &&
-                               match_expr_eval(o, x->u.binary.right,
-                                               bol, eol, ctx, 0));
-               h = match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0);
-               h &= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 0);
+               if (!match_expr_eval(x->u.binary.left, bol, eol, ctx, 0))
+                       return 0;
+               h = match_expr_eval(x->u.binary.right, bol, eol, ctx, 0);
                break;
        case GREP_NODE_OR:
                if (!collect_hits)
-                       return (match_expr_eval(o, x->u.binary.left,
+                       return (match_expr_eval(x->u.binary.left,
                                                bol, eol, ctx, 0) ||
-                               match_expr_eval(o, x->u.binary.right,
+                               match_expr_eval(x->u.binary.right,
                                                bol, eol, ctx, 0));
-               h = match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0);
+               h = match_expr_eval(x->u.binary.left, bol, eol, ctx, 0);
                x->u.binary.left->hit |= h;
-               h |= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 1);
+               h |= match_expr_eval(x->u.binary.right, bol, eol, ctx, 1);
                break;
        default:
                die("Unexpected node type (internal error) %d", x->node);
@@ -424,24 +406,104 @@ static int match_expr(struct grep_opt *opt, char *bol, char *eol,
                      enum grep_context ctx, int collect_hits)
 {
        struct grep_expr *x = opt->pattern_expression;
-       return match_expr_eval(opt, x, bol, eol, ctx, collect_hits);
+       return match_expr_eval(x, bol, eol, ctx, collect_hits);
 }
 
 static int match_line(struct grep_opt *opt, char *bol, char *eol,
                      enum grep_context ctx, int collect_hits)
 {
        struct grep_pat *p;
+       regmatch_t match;
+
        if (opt->extended)
                return match_expr(opt, bol, eol, ctx, collect_hits);
 
        /* we do not call with collect_hits without being extended */
        for (p = opt->pattern_list; p; p = p->next) {
-               if (match_one_pattern(opt, p, bol, eol, ctx))
+               if (match_one_pattern(p, bol, eol, ctx, &match, 0))
                        return 1;
        }
        return 0;
 }
 
+static int match_next_pattern(struct grep_pat *p, char *bol, char *eol,
+                             enum grep_context ctx,
+                             regmatch_t *pmatch, int eflags)
+{
+       regmatch_t match;
+
+       if (!match_one_pattern(p, bol, eol, ctx, &match, eflags))
+               return 0;
+       if (match.rm_so < 0 || match.rm_eo < 0)
+               return 0;
+       if (pmatch->rm_so >= 0 && pmatch->rm_eo >= 0) {
+               if (match.rm_so > pmatch->rm_so)
+                       return 1;
+               if (match.rm_so == pmatch->rm_so && match.rm_eo < pmatch->rm_eo)
+                       return 1;
+       }
+       pmatch->rm_so = match.rm_so;
+       pmatch->rm_eo = match.rm_eo;
+       return 1;
+}
+
+static int next_match(struct grep_opt *opt, char *bol, char *eol,
+                     enum grep_context ctx, regmatch_t *pmatch, int eflags)
+{
+       struct grep_pat *p;
+       int hit = 0;
+
+       pmatch->rm_so = pmatch->rm_eo = -1;
+       if (bol < eol) {
+               for (p = opt->pattern_list; p; p = p->next) {
+                       switch (p->token) {
+                       case GREP_PATTERN: /* atom */
+                       case GREP_PATTERN_HEAD:
+                       case GREP_PATTERN_BODY:
+                               hit |= match_next_pattern(p, bol, eol, ctx,
+                                                         pmatch, eflags);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+       return hit;
+}
+
+static void show_line(struct grep_opt *opt, char *bol, char *eol,
+                     const char *name, unsigned lno, char sign)
+{
+       int rest = eol - bol;
+
+       if (opt->null_following_name)
+               sign = '\0';
+       if (opt->pathname)
+               printf("%s%c", name, sign);
+       if (opt->linenum)
+               printf("%d%c", lno, sign);
+       if (opt->color) {
+               regmatch_t match;
+               enum grep_context ctx = GREP_CONTEXT_BODY;
+               int ch = *eol;
+               int eflags = 0;
+
+               *eol = '\0';
+               while (next_match(opt, bol, eol, ctx, &match, eflags)) {
+                       printf("%.*s%s%.*s%s",
+                              (int)match.rm_so, bol,
+                              opt->color_match,
+                              (int)(match.rm_eo - match.rm_so), bol + match.rm_so,
+                              GIT_COLOR_RESET);
+                       bol += match.rm_eo;
+                       rest -= match.rm_eo;
+                       eflags = REG_NOTBOL;
+               }
+               *eol = ch;
+       }
+       printf("%.*s\n", rest, bol);
+}
+
 static int grep_buffer_1(struct grep_opt *opt, const char *name,
                         char *buf, unsigned long size, int collect_hits)
 {
diff --git a/grep.h b/grep.h
index 5102ce335d29811dd448e173f2e90e8d03b5f011..a67005de62d1442e7ba6a8dc27320225a0d55819 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -1,5 +1,6 @@
 #ifndef GREP_H
 #define GREP_H
+#include "color.h"
 
 enum grep_pat_token {
        GREP_PATTERN,
@@ -31,6 +32,7 @@ struct grep_pat {
        enum grep_header_field field;
        regex_t regexp;
        unsigned fixed:1;
+       unsigned word_regexp:1;
 };
 
 enum grep_expr_node {
@@ -76,6 +78,9 @@ struct grep_opt {
        unsigned relative:1;
        unsigned pathname:1;
        unsigned null_following_name:1;
+       int color;
+       char color_match[COLOR_MAXLEN];
+       const char *color_external;
        int regflags;
        unsigned pre_context;
        unsigned post_context;
index 30d2d340418f7f40b77823b1b58b307985347bdf..48e5f38fe0f8848ffe0941d48eae10b8edc14dd8 100644 (file)
@@ -816,7 +816,7 @@ static void finish_request(struct transfer_request *request)
 #ifdef USE_CURL_MULTI
 static int fill_active_slot(void *unused)
 {
-       struct transfer_request *request = request_queue_head;
+       struct transfer_request *request;
 
        if (aborted)
                return 0;
@@ -1792,21 +1792,8 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
        return 1;
 }
 
-static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct ref *ref;
-       int len = strlen(refname) + 1;
-       ref = xcalloc(1, sizeof(*ref) + len);
-       hashcpy(ref->new_sha1, sha1);
-       memcpy(ref->name, refname, len);
-       *local_tail = ref;
-       local_tail = &ref->next;
-       return 0;
-}
-
 static void one_remote_ref(char *refname)
 {
        struct ref *ref;
@@ -1839,12 +1826,6 @@ static void one_remote_ref(char *refname)
        remote_tail = &ref->next;
 }
 
-static void get_local_heads(void)
-{
-       local_tail = &local_refs;
-       for_each_ref(one_local_ref, NULL);
-}
-
 static void get_dav_remote_heads(void)
 {
        remote_tail = &remote_refs;
@@ -1862,55 +1843,6 @@ static int is_zero_sha1(const unsigned char *sha1)
        return 1;
 }
 
-static void unmark_and_free(struct commit_list *list, unsigned int mark)
-{
-       while (list) {
-               struct commit_list *temp = list;
-               temp->item->object.flags &= ~mark;
-               list = temp->next;
-               free(temp);
-       }
-}
-
-static int ref_newer(const unsigned char *new_sha1,
-                    const unsigned char *old_sha1)
-{
-       struct object *o;
-       struct commit *old, *new;
-       struct commit_list *list, *used;
-       int found = 0;
-
-       /* Both new and old must be commit-ish and new is descendant of
-        * old.  Otherwise we require --force.
-        */
-       o = deref_tag(parse_object(old_sha1), NULL, 0);
-       if (!o || o->type != OBJ_COMMIT)
-               return 0;
-       old = (struct commit *) o;
-
-       o = deref_tag(parse_object(new_sha1), NULL, 0);
-       if (!o || o->type != OBJ_COMMIT)
-               return 0;
-       new = (struct commit *) o;
-
-       if (parse_commit(new) < 0)
-               return 0;
-
-       used = list = NULL;
-       commit_list_insert(new, &list);
-       while (list) {
-               new = pop_most_recent_commit(&list, TMP_MARK);
-               commit_list_insert(new, &used);
-               if (new == old) {
-                       found = 1;
-                       break;
-               }
-       }
-       unmark_and_free(list, TMP_MARK);
-       unmark_and_free(used, TMP_MARK);
-       return found;
-}
-
 static void add_remote_info_ref(struct remote_ls_ctx *ls)
 {
        struct strbuf *buf = (struct strbuf *)ls->userData;
@@ -2195,7 +2127,7 @@ int main(int argc, char **argv)
        int rc = 0;
        int i;
        int new_refs;
-       struct ref *ref;
+       struct ref *ref, *local_refs;
        char *rewritten_url = NULL;
 
        git_extract_argv0_path(argv[0]);
@@ -2302,7 +2234,7 @@ int main(int argc, char **argv)
                fetch_indices();
 
        /* Get a list of all local and remote heads to validate refspecs */
-       get_local_heads();
+       local_refs = get_local_heads();
        fprintf(stderr, "Fetching remote heads...\n");
        get_dav_remote_heads();
 
index cb518eb613fdce7482a243ad9075df64ab1a4321..8154cb2116da9257ecf286c46f77fc1ed2a62afc 100644 (file)
@@ -579,7 +579,7 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
                        n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen);
                        free(cmd->cb.data);
                        if (n != cmd->cb.dlen ||
-                           (n = socket_write(&imap->buf.sock, "\r\n", 2)) != 2) {
+                           socket_write(&imap->buf.sock, "\r\n", 2) != 2) {
                                free(cmd->cmd);
                                free(cmd);
                                return NULL;
index 7fee8725333860dbbd13d8de5ae7baf1ef33976d..75468228d3933cc86c79f3595f7ff5e6b643cd7b 100644 (file)
@@ -232,7 +232,7 @@ static void free_base_data(struct base_data *c)
 
 static void prune_base_data(struct base_data *retain)
 {
-       struct base_data *b = base_cache;
+       struct base_data *b;
        for (b = base_cache;
             base_cache_used > delta_base_cache_limit && b;
             b = b->child) {
index ee853b990d8bfb15e0058fefbbd267bd58ed40fc..3e1bc3e07f234089656397361b2b83b59bdc19a7 100644 (file)
@@ -801,22 +801,19 @@ static int process_renames(struct merge_options *o,
        }
 
        for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {
-               int compare;
                char *src;
-               struct string_list *renames1, *renames2, *renames2Dst;
+               struct string_list *renames1, *renames2Dst;
                struct rename *ren1 = NULL, *ren2 = NULL;
                const char *branch1, *branch2;
                const char *ren1_src, *ren1_dst;
 
                if (i >= a_renames->nr) {
-                       compare = 1;
                        ren2 = b_renames->items[j++].util;
                } else if (j >= b_renames->nr) {
-                       compare = -1;
                        ren1 = a_renames->items[i++].util;
                } else {
-                       compare = strcmp(a_renames->items[i].string,
-                                       b_renames->items[j].string);
+                       int compare = strcmp(a_renames->items[i].string,
+                                            b_renames->items[j].string);
                        if (compare <= 0)
                                ren1 = a_renames->items[i++].util;
                        if (compare >= 0)
@@ -826,14 +823,12 @@ static int process_renames(struct merge_options *o,
                /* TODO: refactor, so that 1/2 are not needed */
                if (ren1) {
                        renames1 = a_renames;
-                       renames2 = b_renames;
                        renames2Dst = &b_by_dst;
                        branch1 = o->branch1;
                        branch2 = o->branch2;
                } else {
                        struct rename *tmp;
                        renames1 = b_renames;
-                       renames2 = a_renames;
                        renames2Dst = &a_by_dst;
                        branch1 = o->branch2;
                        branch2 = o->branch1;
index c0184080998734450b250aa7dc72c427e1ecac8a..efa70245f19ef3493cd701ea20505203a466d65e 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -135,7 +135,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
        int namelen;
        unsigned long time;
        int tz;
-       const char *filler = "    ";
 
        if (fmt == CMIT_FMT_ONELINE)
                return;
@@ -154,7 +153,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
                while (line < name_tail && isspace(name_tail[-1]))
                        name_tail--;
                display_name_length = name_tail - line;
-               filler = "";
                strbuf_addstr(sb, "From: ");
                add_rfc2047(sb, line, display_name_length, encoding);
                strbuf_add(sb, name_tail, namelen - display_name_length);
@@ -162,7 +160,7 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
        } else {
                strbuf_addf(sb, "%s: %.*s%.*s\n", what,
                              (fmt == CMIT_FMT_FULLER) ? 4 : 0,
-                             filler, namelen, line);
+                             "    ", namelen, line);
        }
        switch (fmt) {
        case CMIT_FMT_MEDIUM:
index 940ec76fdf231ac1345079ca2dc5da88925bcfb6..3f587110cb9d7be1890b7db68a0bdac35d48cd35 100644 (file)
@@ -67,8 +67,10 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
  */
 void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 {
-       ce->ce_ctime = st->st_ctime;
-       ce->ce_mtime = st->st_mtime;
+       ce->ce_ctime.sec = (unsigned int)st->st_ctime;
+       ce->ce_mtime.sec = (unsigned int)st->st_mtime;
+       ce->ce_ctime.nsec = ST_CTIME_NSEC(*st);
+       ce->ce_mtime.nsec = ST_MTIME_NSEC(*st);
        ce->ce_dev = st->st_dev;
        ce->ce_ino = st->st_ino;
        ce->ce_uid = st->st_uid;
@@ -196,11 +198,18 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
        default:
                die("internal error: ce_mode is %o", ce->ce_mode);
        }
-       if (ce->ce_mtime != (unsigned int) st->st_mtime)
+       if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
                changed |= MTIME_CHANGED;
-       if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)
+       if (trust_ctime && ce->ce_ctime.sec != (unsigned int)st->st_ctime)
                changed |= CTIME_CHANGED;
 
+#ifdef USE_NSEC
+       if (ce->ce_mtime.nsec != ST_MTIME_NSEC(*st))
+               changed |= MTIME_CHANGED;
+       if (trust_ctime && ce->ce_ctime.nsec != ST_CTIME_NSEC(*st))
+               changed |= CTIME_CHANGED;
+#endif
+
        if (ce->ce_uid != (unsigned int) st->st_uid ||
            ce->ce_gid != (unsigned int) st->st_gid)
                changed |= OWNER_CHANGED;
@@ -232,8 +241,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
 {
        return (!S_ISGITLINK(ce->ce_mode) &&
-               istate->timestamp &&
-               ((unsigned int)istate->timestamp) <= ce->ce_mtime);
+               istate->timestamp.sec &&
+#ifdef USE_NSEC
+                /* nanosecond timestamped files can also be racy! */
+               (istate->timestamp.sec < ce->ce_mtime.sec ||
+                (istate->timestamp.sec == ce->ce_mtime.sec &&
+                 istate->timestamp.nsec <= ce->ce_mtime.nsec))
+#else
+               istate->timestamp.sec <= ce->ce_mtime.sec
+#endif
+                );
 }
 
 int ie_match_stat(const struct index_state *istate,
@@ -443,6 +460,26 @@ int remove_index_entry_at(struct index_state *istate, int pos)
        return 1;
 }
 
+/*
+ * Remove all cache ententries marked for removal, that is where
+ * CE_REMOVE is set in ce_flags.  This is much more effective than
+ * calling remove_index_entry_at() for each entry to be removed.
+ */
+void remove_marked_cache_entries(struct index_state *istate)
+{
+       struct cache_entry **ce_array = istate->cache;
+       unsigned int i, j;
+
+       for (i = j = 0; i < istate->cache_nr; i++) {
+               if (ce_array[i]->ce_flags & CE_REMOVE)
+                       remove_name_hash(ce_array[i]);
+               else
+                       ce_array[j++] = ce_array[i];
+       }
+       istate->cache_changed = 1;
+       istate->cache_nr = j;
+}
+
 int remove_file_from_index(struct index_state *istate, const char *path)
 {
        int pos = index_name_pos(istate, path, strlen(path));
@@ -1139,8 +1176,10 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
        size_t len;
        const char *name;
 
-       ce->ce_ctime = ntohl(ondisk->ctime.sec);
-       ce->ce_mtime = ntohl(ondisk->mtime.sec);
+       ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
+       ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
+       ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
+       ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
        ce->ce_dev   = ntohl(ondisk->dev);
        ce->ce_ino   = ntohl(ondisk->ino);
        ce->ce_mode  = ntohl(ondisk->mode);
@@ -1206,7 +1245,8 @@ int read_index_from(struct index_state *istate, const char *path)
                return istate->cache_nr;
 
        errno = ENOENT;
-       istate->timestamp = 0;
+       istate->timestamp.sec = 0;
+       istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
        if (fd < 0) {
                if (errno == ENOENT)
@@ -1258,7 +1298,9 @@ int read_index_from(struct index_state *istate, const char *path)
                src_offset += ondisk_ce_size(ce);
                dst_offset += ce_size(ce);
        }
-       istate->timestamp = st.st_mtime;
+       istate->timestamp.sec = st.st_mtime;
+       istate->timestamp.nsec = ST_MTIME_NSEC(st);
+
        while (src_offset <= mmap_size - 20 - 8) {
                /* After an array of active_nr index entries,
                 * there can be arbitrary number of extended
@@ -1288,14 +1330,15 @@ int read_index_from(struct index_state *istate, const char *path)
 
 int is_index_unborn(struct index_state *istate)
 {
-       return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
+       return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);
 }
 
 int discard_index(struct index_state *istate)
 {
        istate->cache_nr = 0;
        istate->cache_changed = 0;
-       istate->timestamp = 0;
+       istate->timestamp.sec = 0;
+       istate->timestamp.nsec = 0;
        istate->name_hash_initialized = 0;
        free_hash(&istate->name_hash);
        cache_tree_free(&(istate->cache_tree));
@@ -1441,10 +1484,10 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
        struct ondisk_cache_entry *ondisk = xcalloc(1, size);
        char *name;
 
-       ondisk->ctime.sec = htonl(ce->ce_ctime);
-       ondisk->ctime.nsec = 0;
-       ondisk->mtime.sec = htonl(ce->ce_mtime);
-       ondisk->mtime.nsec = 0;
+       ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
+       ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
+       ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
+       ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
        ondisk->dev  = htonl(ce->ce_dev);
        ondisk->ino  = htonl(ce->ce_ino);
        ondisk->mode = htonl(ce->ce_mode);
@@ -1466,13 +1509,14 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
        return ce_write(c, fd, ondisk, size);
 }
 
-int write_index(const struct index_state *istate, int newfd)
+int write_index(struct index_state *istate, int newfd)
 {
        git_SHA_CTX c;
        struct cache_header hdr;
        int i, err, removed, extended;
        struct cache_entry **cache = istate->cache;
        int entries = istate->cache_nr;
+       struct stat st;
 
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
@@ -1516,7 +1560,12 @@ int write_index(const struct index_state *istate, int newfd)
                if (err)
                        return -1;
        }
-       return ce_flush(&c, newfd);
+
+       if (ce_flush(&c, newfd) || fstat(newfd, &st))
+               return -1;
+       istate->timestamp.sec = (unsigned int)st.st_mtime;
+       istate->timestamp.nsec = ST_MTIME_NSEC(st);
+       return 0;
 }
 
 /*
diff --git a/refs.c b/refs.c
index 6eb5f5384611bb5d159d892a1bfd120d72e54b9b..8d3c502a151648abefc4afae70d1ec5f7b5d41b6 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch)
 int check_ref_format(const char *ref)
 {
        int ch, level, bad_type;
+       int ret = CHECK_REF_FORMAT_OK;
        const char *cp = ref;
 
        level = 0;
@@ -709,18 +710,18 @@ int check_ref_format(const char *ref)
                        return CHECK_REF_FORMAT_ERROR;
                bad_type = bad_ref_char(ch);
                if (bad_type) {
-                       return (bad_type == 2 && !*cp)
-                               ? CHECK_REF_FORMAT_WILDCARD
-                               : CHECK_REF_FORMAT_ERROR;
+                       if (bad_type == 2 && (!*cp || *cp == '/') &&
+                           ret == CHECK_REF_FORMAT_OK)
+                               ret = CHECK_REF_FORMAT_WILDCARD;
+                       else
+                               return CHECK_REF_FORMAT_ERROR;
                }
 
                /* scan the rest of the path component */
                while ((ch = *cp++) != 0) {
                        bad_type = bad_ref_char(ch);
                        if (bad_type) {
-                               return (bad_type == 2 && !*cp)
-                                       ? CHECK_REF_FORMAT_WILDCARD
-                                       : CHECK_REF_FORMAT_ERROR;
+                               return CHECK_REF_FORMAT_ERROR;
                        }
                        if (ch == '/')
                                break;
@@ -731,7 +732,7 @@ int check_ref_format(const char *ref)
                if (!ch) {
                        if (level < 2)
                                return CHECK_REF_FORMAT_ONELEVEL;
-                       return CHECK_REF_FORMAT_OK;
+                       return ret;
                }
        }
 }
@@ -1628,10 +1629,10 @@ int update_ref(const char *action, const char *refname,
        return 0;
 }
 
-struct ref *find_ref_by_name(struct ref *list, const char *name)
+struct ref *find_ref_by_name(const struct ref *list, const char *name)
 {
        for ( ; list; list = list->next)
                if (!strcmp(list->name, name))
-                       return list;
+                       return (struct ref *)list;
        return NULL;
 }
index d7079c6dd871dc1b482d347d013438fe30cc0908..e5d6b100d738c388bff91bff68b14f69dea87166 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -5,13 +5,14 @@
 #include "diff.h"
 #include "revision.h"
 #include "dir.h"
+#include "tag.h"
 
 static struct refspec s_tag_refspec = {
        0,
        1,
        0,
-       "refs/tags/",
-       "refs/tags/"
+       "refs/tags/*",
+       "refs/tags/*"
 };
 
 const struct refspec *tag_refspec = &s_tag_refspec;
@@ -38,6 +39,7 @@ static int branches_nr;
 
 static struct branch *current_branch;
 static const char *default_remote_name;
+static int explicit_default_remote_name;
 
 static struct rewrite **rewrite;
 static int rewrite_alloc;
@@ -330,8 +332,10 @@ static int handle_config(const char *key, const char *value, void *cb)
                        if (!value)
                                return config_error_nonbool(key);
                        branch->remote_name = xstrdup(value);
-                       if (branch == current_branch)
+                       if (branch == current_branch) {
                                default_remote_name = branch->remote_name;
+                               explicit_default_remote_name = 1;
+                       }
                } else if (!strcmp(subkey, ".merge")) {
                        if (!value)
                                return config_error_nonbool(key);
@@ -451,16 +455,11 @@ static void read_config(void)
  */
 static int verify_refname(char *name, int is_glob)
 {
-       int result, len = -1;
+       int result;
 
-       if (is_glob) {
-               len = strlen(name);
-               assert(name[len - 1] == '/');
-               name[len - 1] = '\0';
-       }
        result = check_ref_format(name);
-       if (is_glob)
-               name[len - 1] = '/';
+       if (is_glob && result == CHECK_REF_FORMAT_WILDCARD)
+               result = CHECK_REF_FORMAT_OK;
        return result;
 }
 
@@ -495,7 +494,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                int is_glob;
                const char *lhs, *rhs;
 
-               llen = is_glob = 0;
+               is_glob = 0;
 
                lhs = refspec[i];
                if (*lhs == '+') {
@@ -516,16 +515,15 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
 
                if (rhs) {
                        size_t rlen = strlen(++rhs);
-                       is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
-                       rs[i].dst = xstrndup(rhs, rlen - is_glob);
+                       is_glob = (1 <= rlen && strchr(rhs, '*'));
+                       rs[i].dst = xstrndup(rhs, rlen);
                }
 
                llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
-               if (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2)) {
+               if (1 <= llen && memchr(lhs, '*', llen)) {
                        if ((rhs && !is_glob) || (!rhs && fetch))
                                goto invalid;
                        is_glob = 1;
-                       llen--;
                } else if (rhs && is_glob) {
                        goto invalid;
                }
@@ -643,10 +641,16 @@ static int valid_remote_nick(const char *name)
 struct remote *remote_get(const char *name)
 {
        struct remote *ret;
+       int name_given = 0;
 
        read_config();
-       if (!name)
+       if (name)
+               name_given = 1;
+       else {
                name = default_remote_name;
+               name_given = explicit_default_remote_name;
+       }
+
        ret = make_remote(name, 0);
        if (valid_remote_nick(name)) {
                if (!ret->url)
@@ -654,7 +658,7 @@ struct remote *remote_get(const char *name)
                if (!ret->url)
                        read_branches_file(ret);
        }
-       if (!ret->url)
+       if (name_given && !ret->url)
                add_url_alias(ret, name);
        if (!ret->url)
                return NULL;
@@ -719,6 +723,41 @@ int remote_has_url(struct remote *remote, const char *url)
        return 0;
 }
 
+static int match_name_with_pattern(const char *key, const char *name,
+                                  const char *value, char **result)
+{
+       const char *kstar = strchr(key, '*');
+       size_t klen;
+       size_t ksuffixlen;
+       size_t namelen;
+       int ret;
+       if (!kstar)
+               die("Key '%s' of pattern had no '*'", key);
+       klen = kstar - key;
+       ksuffixlen = strlen(kstar + 1);
+       namelen = strlen(name);
+       ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&
+               !memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen);
+       if (ret && value) {
+               const char *vstar = strchr(value, '*');
+               size_t vlen;
+               size_t vsuffixlen;
+               if (!vstar)
+                       die("Value '%s' of pattern has no '*'", value);
+               vlen = vstar - value;
+               vsuffixlen = strlen(vstar + 1);
+               *result = xmalloc(vlen + vsuffixlen +
+                                 strlen(name) -
+                                 klen - ksuffixlen + 1);
+               strncpy(*result, value, vlen);
+               strncpy(*result + vlen,
+                       name + klen, namelen - klen - ksuffixlen);
+               strcpy(*result + vlen + namelen - klen - ksuffixlen,
+                      vstar + 1);
+       }
+       return ret;
+}
+
 int remote_find_tracking(struct remote *remote, struct refspec *refspec)
 {
        int find_src = refspec->src == NULL;
@@ -742,13 +781,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
                if (!fetch->dst)
                        continue;
                if (fetch->pattern) {
-                       if (!prefixcmp(needle, key)) {
-                               *result = xmalloc(strlen(value) +
-                                                 strlen(needle) -
-                                                 strlen(key) + 1);
-                               strcpy(*result, value);
-                               strcpy(*result + strlen(value),
-                                      needle + strlen(key));
+                       if (match_name_with_pattern(key, needle, value, result)) {
                                refspec->force = fetch->force;
                                return 0;
                        }
@@ -778,10 +811,18 @@ struct ref *alloc_ref(const char *name)
 
 static struct ref *copy_ref(const struct ref *ref)
 {
-       struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1);
-       memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1);
-       ret->next = NULL;
-       return ret;
+       struct ref *cpy;
+       size_t len;
+       if (!ref)
+               return NULL;
+       len = strlen(ref->name);
+       cpy = xmalloc(sizeof(struct ref) + len + 1);
+       memcpy(cpy, ref, sizeof(struct ref) + len + 1);
+       cpy->next = NULL;
+       cpy->symref = ref->symref ? xstrdup(ref->symref) : NULL;
+       cpy->remote_status = ref->remote_status ? xstrdup(ref->remote_status) : NULL;
+       cpy->peer_ref = copy_ref(ref->peer_ref);
+       return cpy;
 }
 
 struct ref *copy_ref_list(const struct ref *ref)
@@ -800,6 +841,7 @@ static void free_ref(struct ref *ref)
 {
        if (!ref)
                return;
+       free_ref(ref->peer_ref);
        free(ref->remote_status);
        free(ref->symref);
        free(ref);
@@ -810,7 +852,6 @@ void free_refs(struct ref *ref)
        struct ref *next;
        while (ref) {
                next = ref->next;
-               free(ref->peer_ref);
                free_ref(ref);
                ref = next;
        }
@@ -927,6 +968,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
                          struct refspec *rs)
 {
        struct ref *matched_src, *matched_dst;
+       int copy_src;
 
        const char *dst_value = rs->dst;
        char *dst_guess;
@@ -937,6 +979,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
        matched_src = matched_dst = NULL;
        switch (count_refspec_match(rs->src, src, &matched_src)) {
        case 1:
+               copy_src = 1;
                break;
        case 0:
                /* The source could be in the get_sha1() format
@@ -946,6 +989,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
                matched_src = try_explicit_object_name(rs->src);
                if (!matched_src)
                        return error("src refspec %s does not match any.", rs->src);
+               copy_src = 0;
                break;
        default:
                return error("src refspec %s matches more than one.", rs->src);
@@ -991,7 +1035,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
                return error("dst ref %s receives from more than one src.",
                      matched_dst->name);
        else {
-               matched_dst->peer_ref = matched_src;
+               matched_dst->peer_ref = copy_src ? copy_ref(matched_src) : matched_src;
                matched_dst->force = rs->force;
        }
        return 0;
@@ -1020,7 +1064,8 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
                        continue;
                }
 
-               if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
+               if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name,
+                                                            NULL, NULL))
                        return rs + i;
        }
        if (matching_refs != -1)
@@ -1040,6 +1085,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
        struct refspec *rs;
        int send_all = flags & MATCH_REFS_ALL;
        int send_mirror = flags & MATCH_REFS_MIRROR;
+       int errs;
        static const char *default_refspec[] = { ":", 0 };
 
        if (!nr_refspec) {
@@ -1047,8 +1093,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
                refspec = default_refspec;
        }
        rs = parse_push_refspec(nr_refspec, (const char **) refspec);
-       if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
-               return -1;
+       errs = match_explicit_refs(src, dst, dst_tail, rs, nr_refspec);
 
        /* pick the remainder */
        for ( ; src; src = src->next) {
@@ -1074,11 +1119,9 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
 
                } else {
                        const char *dst_side = pat->dst ? pat->dst : pat->src;
-                       dst_name = xmalloc(strlen(dst_side) +
-                                          strlen(src->name) -
-                                          strlen(pat->src) + 2);
-                       strcpy(dst_name, dst_side);
-                       strcat(dst_name, src->name + strlen(pat->src));
+                       if (!match_name_with_pattern(pat->src, src->name,
+                                                    dst_side, &dst_name))
+                               die("Didn't think it matches any more");
                }
                dst_peer = find_ref_by_name(dst, dst_name);
                if (dst_peer) {
@@ -1099,11 +1142,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
                        dst_peer = make_linked_ref(dst_name, dst_tail);
                        hashcpy(dst_peer->new_sha1, src->new_sha1);
                }
-               dst_peer->peer_ref = src;
+               dst_peer->peer_ref = copy_ref(src);
                dst_peer->force = pat->force;
        free_name:
                free(dst_name);
        }
+       if (errs)
+               return -1;
        return 0;
 }
 
@@ -1154,19 +1199,17 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
        struct ref *ret = NULL;
        struct ref **tail = &ret;
 
-       int remote_prefix_len = strlen(refspec->src);
-       int local_prefix_len = strlen(refspec->dst);
+       char *expn_name;
 
        for (ref = remote_refs; ref; ref = ref->next) {
                if (strchr(ref->name, '^'))
                        continue; /* a dereference item */
-               if (!prefixcmp(ref->name, refspec->src)) {
-                       const char *match;
+               if (match_name_with_pattern(refspec->src, ref->name,
+                                           refspec->dst, &expn_name)) {
                        struct ref *cpy = copy_ref(ref);
-                       match = ref->name + remote_prefix_len;
 
-                       cpy->peer_ref = alloc_ref_with_prefix(refspec->dst,
-                                       local_prefix_len, match);
+                       cpy->peer_ref = alloc_ref(expn_name);
+                       free(expn_name);
                        if (refspec->force)
                                cpy->peer_ref->force = 1;
                        *tail = cpy;
@@ -1269,6 +1312,54 @@ int resolve_remote_symref(struct ref *ref, struct ref *list)
        return 1;
 }
 
+static void unmark_and_free(struct commit_list *list, unsigned int mark)
+{
+       while (list) {
+               struct commit_list *temp = list;
+               temp->item->object.flags &= ~mark;
+               list = temp->next;
+               free(temp);
+       }
+}
+
+int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
+{
+       struct object *o;
+       struct commit *old, *new;
+       struct commit_list *list, *used;
+       int found = 0;
+
+       /* Both new and old must be commit-ish and new is descendant of
+        * old.  Otherwise we require --force.
+        */
+       o = deref_tag(parse_object(old_sha1), NULL, 0);
+       if (!o || o->type != OBJ_COMMIT)
+               return 0;
+       old = (struct commit *) o;
+
+       o = deref_tag(parse_object(new_sha1), NULL, 0);
+       if (!o || o->type != OBJ_COMMIT)
+               return 0;
+       new = (struct commit *) o;
+
+       if (parse_commit(new) < 0)
+               return 0;
+
+       used = list = NULL;
+       commit_list_insert(new, &list);
+       while (list) {
+               new = pop_most_recent_commit(&list, TMP_MARK);
+               commit_list_insert(new, &used);
+               if (new == old) {
+                       found = 1;
+                       break;
+               }
+       }
+       unmark_and_free(list, TMP_MARK);
+       unmark_and_free(used, TMP_MARK);
+       return found;
+}
+
 /*
  * Return true if there is anything to report, otherwise false.
  */
@@ -1376,3 +1467,68 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                            base, num_ours, num_theirs);
        return 1;
 }
+
+static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+       struct ref ***local_tail = cb_data;
+       struct ref *ref;
+       int len;
+
+       /* we already know it starts with refs/ to get here */
+       if (check_ref_format(refname + 5))
+               return 0;
+
+       len = strlen(refname) + 1;
+       ref = xcalloc(1, sizeof(*ref) + len);
+       hashcpy(ref->new_sha1, sha1);
+       memcpy(ref->name, refname, len);
+       **local_tail = ref;
+       *local_tail = &ref->next;
+       return 0;
+}
+
+struct ref *get_local_heads(void)
+{
+       struct ref *local_refs, **local_tail = &local_refs;
+       for_each_ref(one_local_ref, &local_tail);
+       return local_refs;
+}
+
+struct ref *guess_remote_head(const struct ref *head,
+                             const struct ref *refs,
+                             int all)
+{
+       const struct ref *r;
+       struct ref *list = NULL;
+       struct ref **tail = &list;
+
+       if (!head)
+               return NULL;
+
+       /*
+        * Some transports support directly peeking at
+        * where HEAD points; if that is the case, then
+        * we don't have to guess.
+        */
+       if (head->symref)
+               return copy_ref(find_ref_by_name(refs, head->symref));
+
+       /* If refs/heads/master could be right, it is. */
+       if (!all) {
+               r = find_ref_by_name(refs, "refs/heads/master");
+               if (r && !hashcmp(r->old_sha1, head->old_sha1))
+                       return copy_ref(r);
+       }
+
+       /* Look for another ref that points there */
+       for (r = refs; r; r = r->next) {
+               if (r != head && !hashcmp(r->old_sha1, head->old_sha1)) {
+                       *tail = copy_ref(r);
+                       tail = &((*tail)->next);
+                       if (!all)
+                               break;
+               }
+       }
+
+       return list;
+}
index a46a5be131caf1d1d71f97cab3c3ba2cebb6386c..de3d21b6626f64ffc54904eec6f26a614feab30a 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -74,6 +74,7 @@ int check_ref_type(const struct ref *ref, int flags);
 void free_refs(struct ref *ref);
 
 int resolve_remote_symref(struct ref *ref, struct ref *list);
+int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);
 
 /*
  * Removes and frees any duplicate refs in the map.
@@ -137,4 +138,15 @@ enum match_refs_flags {
 int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs);
 int format_tracking_info(struct branch *branch, struct strbuf *sb);
 
+struct ref *get_local_heads(void);
+/*
+ * Find refs from a list which are likely to be pointed to by the given HEAD
+ * ref. If 'all' is false, returns the most likely ref; otherwise, returns a
+ * list of all candidate refs. If no match is found (or 'head' is NULL),
+ * returns NULL. All returns are newly allocated and should be freed.
+ */
+struct ref *guess_remote_head(const struct ref *head,
+                             const struct ref *refs,
+                             int all);
+
 #endif
index cca3360546dabf9f018b882f690bd1dea9de534d..899b1ff36619d0077dced9da77f538ab98396a83 100644 (file)
@@ -19,7 +19,7 @@
 
 #define FIX_SIZE 10  /* large enough for any of the above */
 
-int recv_sideband(const char *me, int in_stream, int out, int err)
+int recv_sideband(const char *me, int in_stream, int out)
 {
        unsigned pf = strlen(PREFIX);
        unsigned sf;
@@ -41,8 +41,7 @@ int recv_sideband(const char *me, int in_stream, int out, int err)
                if (len == 0)
                        break;
                if (len < 1) {
-                       len = sprintf(buf, "%s: protocol error: no band designator\n", me);
-                       safe_write(err, buf, len);
+                       fprintf(stderr, "%s: protocol error: no band designator\n", me);
                        return SIDEBAND_PROTOCOL_ERROR;
                }
                band = buf[pf] & 0xff;
@@ -50,8 +49,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err)
                switch (band) {
                case 3:
                        buf[pf] = ' ';
-                       buf[pf+1+len] = '\n';
-                       safe_write(err, buf, pf+1+len+1);
+                       buf[pf+1+len] = '\0';
+                       fprintf(stderr, "%s\n", buf);
                        return SIDEBAND_REMOTE_ERROR;
                case 2:
                        buf[pf] = ' ';
@@ -95,12 +94,12 @@ int recv_sideband(const char *me, int in_stream, int out, int err)
                                        memcpy(save, b + brk, sf);
                                        b[brk + sf - 1] = b[brk - 1];
                                        memcpy(b + brk - 1, suffix, sf);
-                                       safe_write(err, b, brk + sf);
+                                       fprintf(stderr, "%.*s", brk + sf, b);
                                        memcpy(b + brk, save, sf);
                                        len -= brk;
                                } else {
                                        int l = brk ? brk : len;
-                                       safe_write(err, b, l);
+                                       fprintf(stderr, "%.*s", l, b);
                                        len -= l;
                                }
 
@@ -112,10 +111,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err)
                        safe_write(out, buf + pf+1, len);
                        continue;
                default:
-                       len = sprintf(buf,
-                                     "%s: protocol error: bad band #%d\n",
-                                     me, band);
-                       safe_write(err, buf, len);
+                       fprintf(stderr, "%s: protocol error: bad band #%d\n",
+                               me, band);
                        return SIDEBAND_PROTOCOL_ERROR;
                }
        }
index a84b6917c7a17b5f8a922540801e98d46aa24431..d72db35d1e0dc109f75b292762013c11b86426aa 100644 (file)
@@ -7,7 +7,7 @@
 #define DEFAULT_PACKET_MAX 1000
 #define LARGE_PACKET_MAX 65520
 
-int recv_sideband(const char *me, int in_stream, int out, int err);
+int recv_sideband(const char *me, int in_stream, int out);
 ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);
 
 #endif
index 6ed06840b856a91f6d215c9a862e064f521384f0..bfbd81632e8d2e5584c4eeac0d17aa4b4c2525d8 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -139,14 +139,11 @@ void strbuf_list_free(struct strbuf **sbs)
 
 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 {
-       int cmp;
-       if (a->len < b->len) {
-               cmp = memcmp(a->buf, b->buf, a->len);
-               return cmp ? cmp : -1;
-       } else {
-               cmp = memcmp(a->buf, b->buf, b->len);
-               return cmp ? cmp : a->len != b->len;
-       }
+       int len = a->len < b->len ? a->len: b->len;
+       int cmp = memcmp(a->buf, b->buf, len);
+       if (cmp)
+               return cmp;
+       return a->len < b->len ? -1: a->len != b->len;
 }
 
 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
index 15e14cf47a586613a62970b393c269728ffbef93..1ac536e638dbbc02deb2d4e4a607cc52f7f7c108 100644 (file)
@@ -92,6 +92,16 @@ struct string_list_item *string_list_lookup(const char *string, struct string_li
        return list->items + i;
 }
 
+int for_each_string_list(string_list_each_func_t fn,
+                        struct string_list *list, void *cb_data)
+{
+       int i, ret = 0;
+       for (i = 0; i < list->nr; i++)
+               if ((ret = fn(&list->items[i], cb_data)))
+                       break;
+       return ret;
+}
+
 void string_list_clear(struct string_list *list, int free_util)
 {
        if (list->items) {
index d32ba05202880733dd76f5465a0ae16753d1fba6..14bbc477decc32618139e912fda22e585d815159 100644 (file)
@@ -20,6 +20,11 @@ void string_list_clear(struct string_list *list, int free_util);
 typedef void (*string_list_clear_func_t)(void *p, const char *str);
 void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);
 
+/* Use this function to iterate over each item */
+typedef int (*string_list_each_func_t)(struct string_list_item *, void *);
+int for_each_string_list(string_list_each_func_t,
+                        struct string_list *list, void *cb_data);
+
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
 int string_list_find_insert_index(const struct string_list *list, const char *string,
index f262b7c44b387f4c60901124c30585b3c059fa73..1d6b35b858020300f502e2a9341b82d4fa8a61fd 100644 (file)
@@ -1,51 +1,54 @@
 #include "cache.h"
 
-static struct cache_def {
-       char path[PATH_MAX + 1];
-       int len;
-       int flags;
-       int track_flags;
-       int prefix_len_stat_func;
-} cache;
-
 /*
  * Returns the length (on a path component basis) of the longest
- * common prefix match of 'name' and the cached path string.
+ * common prefix match of 'name_a' and 'name_b'.
  */
-static inline int longest_match_lstat_cache(int len, const char *name,
-                                           int *previous_slash)
+static int longest_path_match(const char *name_a, int len_a,
+                             const char *name_b, int len_b,
+                             int *previous_slash)
 {
        int max_len, match_len = 0, match_len_prev = 0, i = 0;
 
-       max_len = len < cache.len ? len : cache.len;
-       while (i < max_len && name[i] == cache.path[i]) {
-               if (name[i] == '/') {
+       max_len = len_a < len_b ? len_a : len_b;
+       while (i < max_len && name_a[i] == name_b[i]) {
+               if (name_a[i] == '/') {
                        match_len_prev = match_len;
                        match_len = i;
                }
                i++;
        }
-       /* Is the cached path string a substring of 'name'? */
-       if (i == cache.len && cache.len < len && name[cache.len] == '/') {
-               match_len_prev = match_len;
-               match_len = cache.len;
-       /* Is 'name' a substring of the cached path string? */
-       } else if ((i == len && len < cache.len && cache.path[len] == '/') ||
-                  (i == len && len == cache.len)) {
+       /*
+        * Is 'name_b' a substring of 'name_a', the other way around,
+        * or is 'name_a' and 'name_b' the exact same string?
+        */
+       if (i >= max_len && ((len_a > len_b && name_a[len_b] == '/') ||
+                            (len_a < len_b && name_b[len_a] == '/') ||
+                            (len_a == len_b))) {
                match_len_prev = match_len;
-               match_len = len;
+               match_len = i;
        }
        *previous_slash = match_len_prev;
        return match_len;
 }
 
-static inline void reset_lstat_cache(int track_flags, int prefix_len_stat_func)
+static struct cache_def {
+       char path[PATH_MAX + 1];
+       int len;
+       int flags;
+       int track_flags;
+       int prefix_len_stat_func;
+} cache;
+
+static inline void reset_lstat_cache(void)
 {
        cache.path[0] = '\0';
        cache.len = 0;
        cache.flags = 0;
-       cache.track_flags = track_flags;
-       cache.prefix_len_stat_func = prefix_len_stat_func;
+       /*
+        * The track_flags and prefix_len_stat_func members is only
+        * set by the safeguard rule inside lstat_cache()
+        */
 }
 
 #define FL_DIR      (1 << 0)
@@ -67,7 +70,7 @@ static inline void reset_lstat_cache(int track_flags, int prefix_len_stat_func)
  * of the prefix, where the cache should use the stat() function
  * instead of the lstat() function to test each path component.
  */
-static int lstat_cache(int len, const char *name,
+static int lstat_cache(const char *name, int len,
                       int track_flags, int prefix_len_stat_func)
 {
        int match_len, last_slash, last_slash_dir, previous_slash;
@@ -77,11 +80,13 @@ static int lstat_cache(int len, const char *name,
        if (cache.track_flags != track_flags ||
            cache.prefix_len_stat_func != prefix_len_stat_func) {
                /*
-                * As a safeguard we clear the cache if the values of
-                * track_flags and/or prefix_len_stat_func does not
-                * match with the last supplied values.
+                * As a safeguard rule we clear the cache if the
+                * values of track_flags and/or prefix_len_stat_func
+                * does not match with the last supplied values.
                 */
-               reset_lstat_cache(track_flags, prefix_len_stat_func);
+               reset_lstat_cache();
+               cache.track_flags = track_flags;
+               cache.prefix_len_stat_func = prefix_len_stat_func;
                match_len = last_slash = 0;
        } else {
                /*
@@ -89,7 +94,8 @@ static int lstat_cache(int len, const char *name,
                 * the 2 "excluding" path types.
                 */
                match_len = last_slash =
-                       longest_match_lstat_cache(len, name, &previous_slash);
+                       longest_path_match(name, len, cache.path, cache.len,
+                                          &previous_slash);
                match_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);
                if (match_flags && match_len == cache.len)
                        return match_flags;
@@ -153,7 +159,7 @@ static int lstat_cache(int len, const char *name,
                cache.path[last_slash] = '\0';
                cache.len = last_slash;
                cache.flags = save_flags;
-       } else if (track_flags & FL_DIR &&
+       } else if ((track_flags & FL_DIR) &&
                   last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
                /*
                 * We have a separate test for the directory case,
@@ -170,7 +176,7 @@ static int lstat_cache(int len, const char *name,
                cache.len = last_slash_dir;
                cache.flags = FL_DIR;
        } else {
-               reset_lstat_cache(track_flags, prefix_len_stat_func);
+               reset_lstat_cache();
        }
        return ret_flags;
 }
@@ -179,19 +185,19 @@ static int lstat_cache(int len, const char *name,
  * Invalidate the given 'name' from the cache, if 'name' matches
  * completely with the cache.
  */
-void invalidate_lstat_cache(int len, const char *name)
+void invalidate_lstat_cache(const char *name, int len)
 {
        int match_len, previous_slash;
 
-       match_len = longest_match_lstat_cache(len, name, &previous_slash);
+       match_len = longest_path_match(name, len, cache.path, cache.len,
+                                      &previous_slash);
        if (len == match_len) {
                if ((cache.track_flags & FL_DIR) && previous_slash > 0) {
                        cache.path[previous_slash] = '\0';
                        cache.len = previous_slash;
                        cache.flags = FL_DIR;
                } else
-                       reset_lstat_cache(cache.track_flags,
-                                         cache.prefix_len_stat_func);
+                       reset_lstat_cache();
        }
 }
 
@@ -200,7 +206,7 @@ void invalidate_lstat_cache(int len, const char *name)
  */
 void clear_lstat_cache(void)
 {
-       reset_lstat_cache(0, 0);
+       reset_lstat_cache();
 }
 
 #define USE_ONLY_LSTAT  0
@@ -208,9 +214,9 @@ void clear_lstat_cache(void)
 /*
  * Return non-zero if path 'name' has a leading symlink component
  */
-int has_symlink_leading_path(int len, const char *name)
+int has_symlink_leading_path(const char *name, int len)
 {
-       return lstat_cache(len, name,
+       return lstat_cache(name, len,
                           FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) &
                FL_SYMLINK;
 }
@@ -219,9 +225,9 @@ int has_symlink_leading_path(int len, const char *name)
  * Return non-zero if path 'name' has a leading symlink component or
  * if some leading path component does not exists.
  */
-int has_symlink_or_noent_leading_path(int len, const char *name)
+int has_symlink_or_noent_leading_path(const char *name, int len)
 {
-       return lstat_cache(len, name,
+       return lstat_cache(name, len,
                           FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
                (FL_SYMLINK|FL_NOENT);
 }
@@ -233,9 +239,68 @@ int has_symlink_or_noent_leading_path(int len, const char *name)
  * 'prefix_len', thus we then allow for symlinks in the prefix part as
  * long as those points to real existing directories.
  */
-int has_dirs_only_path(int len, const char *name, int prefix_len)
+int has_dirs_only_path(const char *name, int len, int prefix_len)
 {
-       return lstat_cache(len, name,
+       return lstat_cache(name, len,
                           FL_DIR|FL_FULLPATH, prefix_len) &
                FL_DIR;
 }
+
+static struct removal_def {
+       char path[PATH_MAX];
+       int len;
+} removal;
+
+static void do_remove_scheduled_dirs(int new_len)
+{
+       while (removal.len > new_len) {
+               removal.path[removal.len] = '\0';
+               if (rmdir(removal.path))
+                       break;
+               do {
+                       removal.len--;
+               } while (removal.len > new_len &&
+                        removal.path[removal.len] != '/');
+       }
+       removal.len = new_len;
+       return;
+}
+
+void schedule_dir_for_removal(const char *name, int len)
+{
+       int match_len, last_slash, i, previous_slash;
+
+       match_len = last_slash = i =
+               longest_path_match(name, len, removal.path, removal.len,
+                                  &previous_slash);
+       /* Find last slash inside 'name' */
+       while (i < len) {
+               if (name[i] == '/')
+                       last_slash = i;
+               i++;
+       }
+
+       /*
+        * If we are about to go down the directory tree, we check if
+        * we must first go upwards the tree, such that we then can
+        * remove possible empty directories as we go upwards.
+        */
+       if (match_len < last_slash && match_len < removal.len)
+               do_remove_scheduled_dirs(match_len);
+       /*
+        * If we go deeper down the directory tree, we only need to
+        * save the new path components as we go down.
+        */
+       if (match_len < last_slash) {
+               memcpy(&removal.path[match_len], &name[match_len],
+                      last_slash - match_len);
+               removal.len = last_slash;
+       }
+       return;
+}
+
+void remove_scheduled_dirs(void)
+{
+       do_remove_scheduled_dirs(0);
+       return;
+}
index 67c431d4ebbb32fe8d88a83104485b38d746fa62..de384e6ac3a125e59156abbf897a3371f736bbfa 100644 (file)
@@ -5,7 +5,7 @@ git_svn_id=git""-svn-id
 
 if test -n "$NO_SVN_TESTS"
 then
-       test_expect_success 'skipping git svn tests, NO_SVN_TESTS defined' :
+       say 'skipping git svn tests, NO_SVN_TESTS defined'
        test_done
        exit
 fi
@@ -17,7 +17,7 @@ SVN_TREE=$GIT_SVN_DIR/svn-tree
 svn >/dev/null 2>&1
 if test $? -ne 1
 then
-    test_expect_success 'skipping git svn tests, svn not found' :
+    say 'skipping git svn tests, svn not found'
     test_done
     exit
 fi
@@ -41,7 +41,7 @@ then
        else
                err='Perl SVN libraries not found or unusable, skipping test'
        fi
-       test_expect_success "$err" :
+       say "$err"
        test_done
        exit
 fi
index 86cdebc727c4964899a71366151a7782558153c7..589aaf82149916c43d42fad488567e34b26aebaa 100644 (file)
@@ -94,13 +94,18 @@ prepare_httpd() {
 }
 
 start_httpd() {
-       prepare_httpd
+       prepare_httpd >&3 2>&4
 
        trap 'stop_httpd; die' EXIT
 
        "$LIB_HTTPD_PATH" -d "$HTTPD_ROOT_PATH" \
                -f "$TEST_PATH/apache.conf" $HTTPD_PARA \
-               -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start
+               -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start \
+               >&3 2>&4
+       if ! test $? = 0; then
+               say "skipping test, web server setup failed"
+               test_done
+       fi
 }
 
 stop_httpd() {
index 70df15cbd8339b552a56a95ca0c0893138550201..ddcd5b0efb318a07c18e1bb7b908d1c402a974ed 100755 (executable)
@@ -127,7 +127,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'validate git ls-files output for a known tree.' \
-    'diff current expected'
+    'test_cmp expected current'
 
 test_expect_success \
     'writing tree out with git write-tree.' \
@@ -147,7 +147,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'git ls-tree output for a known tree.' \
-    'diff current expected'
+    'test_cmp expected current'
 
 # This changed in ls-tree pathspec change -- recursive does
 # not show tree nodes anymore.
@@ -166,7 +166,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'git ls-tree -r output for a known tree.' \
-    'diff current expected'
+    'test_cmp expected current'
 
 # But with -r -t we can have both.
 test_expect_success \
@@ -187,7 +187,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'git ls-tree -r output for a known tree.' \
-    'diff current expected'
+    'test_cmp expected current'
 
 test_expect_success \
     'writing partial tree out with git write-tree --prefix.' \
index e5330395fc866b2a913b4b20ecb66f1f2a3bbaff..ae90d34f6cf50c9ffcbb386fb27b8a15042109ed 100755 (executable)
@@ -28,7 +28,7 @@ test_expect_success 'tar archive' '
 
 "$UNZIP" -v >/dev/null 2>&1
 if [ $? -eq 127 ]; then
-       echo "Skipping ZIP test, because unzip was not found"
+       say "Skipping ZIP test, because unzip was not found"
        test_done
        exit
 fi
index 7edf49db3c37982a6d599a39b98ce60ceeb0039b..a449580c8a2e41c665e1f29c56877e271fd17fef 100755 (executable)
@@ -8,6 +8,7 @@ auml=`printf '\xc3\xa4'`
 aumlcdiar=`printf '\x61\xcc\x88'`
 
 case_insensitive=
+unibad=
 test_expect_success 'see if we expect ' '
 
        test_case=test_expect_success
@@ -19,7 +20,6 @@ test_expect_success 'see if we expect ' '
        then
                test_case=test_expect_failure
                case_insensitive=t
-               say "will test on a case insensitive filesystem"
        fi &&
        rm -fr junk &&
        mkdir junk &&
@@ -27,13 +27,18 @@ test_expect_success 'see if we expect ' '
        case "$(cd junk && echo *)" in
        "$aumlcdiar")
                test_unicode=test_expect_failure
-               say "will test on a unicode corrupting filesystem"
+               unibad=t
                ;;
        *)      ;;
        esac &&
        rm -fr junk
 '
 
+test "$case_insensitive" &&
+       say "will test on a case insensitive filesystem"
+test "$unibad" &&
+       say "will test on a unicode corrupting filesystem"
+
 if test "$case_insensitive"
 then
 test_expect_success "detection of case insensitive filesystem during repo init" '
diff --git a/t/t1008-read-tree-overlay.sh b/t/t1008-read-tree-overlay.sh
new file mode 100755 (executable)
index 0000000..f9e0028
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='test multi-tree read-tree without merging'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo one >a &&
+       git add a &&
+       git commit -m initial &&
+       git tag initial &&
+       echo two >b &&
+       git add b &&
+       git commit -m second &&
+       git checkout -b side initial &&
+       echo three >a &&
+       mkdir b &&
+       echo four >b/c &&
+       git add b/c &&
+       git commit -m third
+'
+
+test_expect_success 'multi-read' '
+       git read-tree initial master side &&
+       (echo a; echo b/c) >expect &&
+       git ls-files >actual &&
+       test_cmp expect actual
+'
+
+test_done
+
index 7f7fc36734d96de96801c59af41024db97dc614d..c4414ff576fc03b3234c532bfdcd0f2c8eca9c09 100755 (executable)
@@ -40,6 +40,6 @@ test_expect_success \
 
 test_expect_success \
     'compare commit' \
-    'diff expected commit'
+    'test_cmp expected commit'
 
 test_done
index 3c06842d99a68ea37ce82546b4bfa0cd487b87d7..9c81e041b9f688ebeffacce06b3ff94e153bb9b2 100755 (executable)
@@ -118,7 +118,14 @@ EOF
 
 test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
 
-mv .git/config2 .git/config
+cp .git/config2 .git/config
+
+test_expect_success '--replace-all missing value' '
+       test_must_fail git config --replace-all beta.haha &&
+       test_cmp .git/config2 .git/config
+'
+
+rm .git/config2
 
 test_expect_success '--replace-all' \
        'git config --replace-all beta.haha gamma'
index bd589268fcf459f07ff6c53e43d41e66fe1e7903..54ba3df95f66ecc060adaec6846877c793016aa1 100755 (executable)
@@ -137,7 +137,7 @@ $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000
 EOF
 test_expect_success \
        "verifying $m's log" \
-       "diff expect .git/logs/$m"
+       "test_cmp expect .git/logs/$m"
 rm -rf .git/$m .git/logs expect
 
 test_expect_success \
@@ -168,7 +168,7 @@ $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 +0000
 EOF
 test_expect_success \
        "verifying $m's log" \
-       'diff expect .git/logs/$m'
+       'test_cmp expect .git/logs/$m'
 rm -f .git/$m .git/logs/$m expect
 
 git update-ref $m $D
@@ -272,7 +272,7 @@ $h_FIXED $h_MERGED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151100 +0000      c
 EOF
 test_expect_success \
        'git commit logged updates' \
-       "diff expect .git/logs/$m"
+       "test_cmp expect .git/logs/$m"
 unset h_TEST h_OTHER h_FIXED h_MERGED
 
 test_expect_success \
index 5b24f05573221afb3dc472e78a443ba718db3c60..80af6b9b7ea50652dff6804b589d134207e9258f 100755 (executable)
@@ -70,9 +70,7 @@ test_expect_success setup '
        E=`git rev-parse --verify HEAD:A/B/E` &&
        check_fsck &&
 
-       chmod +x C &&
-       ( test "`git config --bool core.filemode`" != false ||
-         echo executable >>C ) &&
+       test_chmod +x C &&
        git add C &&
        test_tick && git commit -m dragon &&
        L=`git rev-parse --verify HEAD` &&
index b2ddf5ace3581bc2a7056c61b9d43499b2657b65..5a8d52f2ff5ecfea8a1d4f9d39a2ed4a08c822e0 100755 (executable)
@@ -150,7 +150,7 @@ test_expect_success 'add -u resolves unmerged paths' '
        echo 2 >path3 &&
        echo 2 >path5 &&
        git add -u &&
-       git ls-files -s "path?" >actual &&
+       git ls-files -s path1 path2 path3 path4 path5 path6 >actual &&
        {
                echo "100644 $three 0   path1"
                echo "100644 $one 1     path3"
index bc0a3513920cab41e4335b8c1b5163e25e8354d3..36eee0f8ae377e130bdcc20ad882261a83764e38 100755 (executable)
@@ -42,7 +42,7 @@ test_expect_success \
 
 test_expect_success \
     'git ls-files --others should pick up symlinks.' \
-    'diff output expected1'
+    'test_cmp expected1 output'
 
 test_expect_success \
     'git ls-files --others --directory to show output.' \
@@ -51,6 +51,6 @@ test_expect_success \
 
 test_expect_success \
     'git ls-files --others --directory should not get confused.' \
-    'diff output expected2'
+    'test_cmp expected2 output'
 
 test_done
index ec1404063701eef04667d5ffbbb4bdc8051c773b..e4f02a0968331f3a03a6eb1d1bbf2420152caa12 100755 (executable)
@@ -75,7 +75,7 @@ EOF
 
 test_expect_success \
     'validate git ls-files -k output.' \
-    'diff .output .expected'
+    'test_cmp .expected .output'
 
 test_expect_success \
     'git ls-files -m to show modified files.' \
@@ -91,6 +91,6 @@ EOF
 
 test_expect_success \
     'validate git ls-files -m output.' \
-    'diff .output .expected'
+    'test_cmp .expected .output'
 
 test_done
index be7ae5a0041a0d06b40a7152d4c5d495a842a87f..6e391a370208c9a0a6e73facc87f6a0e5081b929 100755 (executable)
@@ -83,9 +83,9 @@ test_expect_success 'rebase a single mode change' '
      git checkout -b modechange HEAD^ &&
      echo 1 > X &&
      git add X &&
-     chmod a+x A &&
+     test_chmod +x A &&
      test_tick &&
-     git commit -m modechange A X &&
+     git commit -m modechange &&
      GIT_TRACE=1 git rebase master
 '
 
index 603b003edff6d32fe8725f119778658c76c806fb..c32ff6682b932b3d9b270de7260a2671d8d07403 100755 (executable)
@@ -459,4 +459,15 @@ test_expect_success 'submodule rebase -i' '
        FAKE_LINES="1 squash 2 3" git rebase -i A
 '
 
+test_expect_success 'avoid unnecessary reset' '
+       git checkout master &&
+       test-chmtime =123456789 file3 &&
+       git update-index --refresh &&
+       HEAD=$(git rev-parse HEAD) &&
+       git rebase -i HEAD~4 &&
+       test $HEAD = $(git rev-parse HEAD) &&
+       MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') &&
+       test 123456789 = $MTIME
+'
+
 test_done
diff --git a/t/t3409-rebase-hook.sh b/t/t3409-rebase-hook.sh
deleted file mode 100755 (executable)
index 098b755..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/bin/sh
-
-test_description='git rebase with its hook(s)'
-
-. ./test-lib.sh
-
-test_expect_success setup '
-       echo hello >file &&
-       git add file &&
-       test_tick &&
-       git commit -m initial &&
-       echo goodbye >file &&
-       git add file &&
-       test_tick &&
-       git commit -m second &&
-       git checkout -b side HEAD^ &&
-       echo world >git &&
-       git add git &&
-       test_tick &&
-       git commit -m side &&
-       git checkout master &&
-       git log --pretty=oneline --abbrev-commit --graph --all &&
-       git branch test side
-'
-
-test_expect_success 'rebase' '
-       git checkout test &&
-       git reset --hard side &&
-       git rebase master &&
-       test "z$(cat git)" = zworld
-'
-
-test_expect_success 'rebase -i' '
-       git checkout test &&
-       git reset --hard side &&
-       EDITOR=true git rebase -i master &&
-       test "z$(cat git)" = zworld
-'
-
-test_expect_success 'setup pre-rebase hook' '
-       mkdir -p .git/hooks &&
-       cat >.git/hooks/pre-rebase <<EOF &&
-#!$SHELL_PATH
-echo "\$1,\$2" >.git/PRE-REBASE-INPUT
-EOF
-       chmod +x .git/hooks/pre-rebase
-'
-
-test_expect_success 'pre-rebase hook gets correct input (1)' '
-       git checkout test &&
-       git reset --hard side &&
-       git rebase master &&
-       test "z$(cat git)" = zworld &&
-       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,
-
-'
-
-test_expect_success 'pre-rebase hook gets correct input (2)' '
-       git checkout test &&
-       git reset --hard side &&
-       git rebase master test &&
-       test "z$(cat git)" = zworld &&
-       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
-'
-
-test_expect_success 'pre-rebase hook gets correct input (3)' '
-       git checkout test &&
-       git reset --hard side &&
-       git checkout master &&
-       git rebase master test &&
-       test "z$(cat git)" = zworld &&
-       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
-'
-
-test_expect_success 'pre-rebase hook gets correct input (4)' '
-       git checkout test &&
-       git reset --hard side &&
-       EDITOR=true git rebase -i master &&
-       test "z$(cat git)" = zworld &&
-       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,
-
-'
-
-test_expect_success 'pre-rebase hook gets correct input (5)' '
-       git checkout test &&
-       git reset --hard side &&
-       EDITOR=true git rebase -i master test &&
-       test "z$(cat git)" = zworld &&
-       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
-'
-
-test_expect_success 'pre-rebase hook gets correct input (6)' '
-       git checkout test &&
-       git reset --hard side &&
-       git checkout master &&
-       EDITOR=true git rebase -i master test &&
-       test "z$(cat git)" = zworld &&
-       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
-'
-
-test_expect_success 'setup pre-rebase hook that fails' '
-       mkdir -p .git/hooks &&
-       cat >.git/hooks/pre-rebase <<EOF &&
-#!$SHELL_PATH
-false
-EOF
-       chmod +x .git/hooks/pre-rebase
-'
-
-test_expect_success 'pre-rebase hook stops rebase (1)' '
-       git checkout test &&
-       git reset --hard side &&
-       test_must_fail git rebase master &&
-       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
-       test 0 = $(git rev-list HEAD...side | wc -l)
-'
-
-test_expect_success 'pre-rebase hook stops rebase (2)' '
-       git checkout test &&
-       git reset --hard side &&
-       (
-               EDITOR=:
-               export EDITOR
-               test_must_fail git rebase -i master
-       ) &&
-       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
-       test 0 = $(git rev-list HEAD...side | wc -l)
-'
-
-test_expect_success 'rebase --no-verify overrides pre-rebase (1)' '
-       git checkout test &&
-       git reset --hard side &&
-       git rebase --no-verify master &&
-       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
-       test "z$(cat git)" = zworld
-'
-
-test_expect_success 'rebase --no-verify overrides pre-rebase (2)' '
-       git checkout test &&
-       git reset --hard side &&
-       EDITOR=true git rebase --no-verify -i master &&
-       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
-       test "z$(cat git)" = zworld
-'
-
-test_done
diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh
new file mode 100755 (executable)
index 0000000..098b755
--- /dev/null
@@ -0,0 +1,146 @@
+#!/bin/sh
+
+test_description='git rebase with its hook(s)'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo hello >file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+       echo goodbye >file &&
+       git add file &&
+       test_tick &&
+       git commit -m second &&
+       git checkout -b side HEAD^ &&
+       echo world >git &&
+       git add git &&
+       test_tick &&
+       git commit -m side &&
+       git checkout master &&
+       git log --pretty=oneline --abbrev-commit --graph --all &&
+       git branch test side
+'
+
+test_expect_success 'rebase' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase master &&
+       test "z$(cat git)" = zworld
+'
+
+test_expect_success 'rebase -i' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase -i master &&
+       test "z$(cat git)" = zworld
+'
+
+test_expect_success 'setup pre-rebase hook' '
+       mkdir -p .git/hooks &&
+       cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+       chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook gets correct input (1)' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase master &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,
+
+'
+
+test_expect_success 'pre-rebase hook gets correct input (2)' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'pre-rebase hook gets correct input (3)' '
+       git checkout test &&
+       git reset --hard side &&
+       git checkout master &&
+       git rebase master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'pre-rebase hook gets correct input (4)' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase -i master &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,
+
+'
+
+test_expect_success 'pre-rebase hook gets correct input (5)' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase -i master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'pre-rebase hook gets correct input (6)' '
+       git checkout test &&
+       git reset --hard side &&
+       git checkout master &&
+       EDITOR=true git rebase -i master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+       mkdir -p .git/hooks &&
+       cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+       chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase (1)' '
+       git checkout test &&
+       git reset --hard side &&
+       test_must_fail git rebase master &&
+       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
+       test 0 = $(git rev-list HEAD...side | wc -l)
+'
+
+test_expect_success 'pre-rebase hook stops rebase (2)' '
+       git checkout test &&
+       git reset --hard side &&
+       (
+               EDITOR=:
+               export EDITOR
+               test_must_fail git rebase -i master
+       ) &&
+       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
+       test 0 = $(git rev-list HEAD...side | wc -l)
+'
+
+test_expect_success 'rebase --no-verify overrides pre-rebase (1)' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase --no-verify master &&
+       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
+       test "z$(cat git)" = zworld
+'
+
+test_expect_success 'rebase --no-verify overrides pre-rebase (2)' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase --no-verify -i master &&
+       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
+       test "z$(cat git)" = zworld
+'
+
+test_done
index 95542e9cfec1d7cc0631521c1c2bef3b7a139af7..2aefbcf47137f9be5cff8786123ce1252656abc6 100755 (executable)
@@ -21,10 +21,11 @@ embedded'
 embedded' &&
      git commit -m 'add files with tabs and newlines'
      else
-         say 'Your filesystem does not allow tabs in filenames.'
          test_tabs=n
      fi"
 
+test "$test_tabs" = n && say 'Your filesystem does not allow tabs in filenames.'
+
 # Later we will try removing an unremovable path to make sure
 # git rm barfs, but if the test is run as root that cannot be
 # arranged.
@@ -112,7 +113,7 @@ test_expect_success \
     'test_must_fail git rm -f baz'
 chmod 775 .
 else
-    test_expect_success 'skipping removal failure (perhaps running as root?)' :
+    say 'skipping removal failure test (perhaps running as root?)'
 fi
 
 test_expect_success \
index 4e92fce1d00a55cfbc39e55b53f95cc309e96ff2..8c1b81e248bced2ccb5e4ff0067996462e89deb8 100755 (executable)
@@ -15,21 +15,10 @@ test_expect_success \
      tree=`git write-tree` &&
      echo $tree'
 
-if [ "$(git config --get core.filemode)" = false ]
-then
-       say 'filemode disabled on the filesystem, using update-index --chmod=+x'
-       test_expect_success \
-           'git update-index --chmod=+x' \
-           'git update-index rezrov &&
-            git update-index --chmod=+x rezrov &&
-            git diff-index $tree >current'
-else
-       test_expect_success \
-           'chmod' \
-           'chmod +x rezrov &&
-            git update-index rezrov &&
-            git diff-index $tree >current'
-fi
+test_expect_success \
+    'chmod' \
+    'test_chmod +x rezrov &&
+     git diff-index $tree >current'
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
index 9cd5a6e68563aede0e69270421b56d1904c34165..426e64e828cfe6efaa7281f30fa8d4e676265107 100755 (executable)
@@ -101,8 +101,7 @@ do
        '' | '#'*) continue ;;
        esac
        test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'`
-       cnt=`expr $test_count + 1`
-       pfx=`printf "%04d" $cnt`
+       pfx=`printf "%04d" $test_count`
        expect="$TEST_DIRECTORY/t4013/diff.$test"
        actual="$pfx-diff.$test"
 
index ebfc4a65908cb1929de299a8540d90db3d9a3a15..f187d15e328aa43f3d7a7b9030158e0128cc4812 100755 (executable)
@@ -16,9 +16,7 @@ test_expect_success setup '
        git checkout -b side &&
 
        for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
-       chmod +x elif &&
-       git update-index file elif &&
-       git update-index --chmod=+x elif &&
+       test_chmod +x elif &&
        git commit -m "Side changes #1" &&
 
        for i in D E F; do echo "$i"; done >>file &&
diff --git a/t/t4017-quiet.sh b/t/t4017-quiet.sh
deleted file mode 100755 (executable)
index e747e84..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/sh
-
-test_description='Return value of diffs'
-
-. ./test-lib.sh
-
-test_expect_success 'setup' '
-       echo 1 >a &&
-       git add . &&
-       git commit -m first &&
-       echo 2 >b &&
-       git add . &&
-       git commit -a -m second
-'
-
-test_expect_success 'git diff-tree HEAD^ HEAD' '
-       git diff-tree --quiet HEAD^ HEAD >cnt
-       test $? = 1 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-tree HEAD^ HEAD -- a' '
-       git diff-tree --quiet HEAD^ HEAD -- a >cnt
-       test $? = 0 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-tree HEAD^ HEAD -- b' '
-       git diff-tree --quiet HEAD^ HEAD -- b >cnt
-       test $? = 1 && test $(wc -l <cnt) = 0
-'
-# this diff outputs one line: sha1 of the given head
-test_expect_success 'echo HEAD | git diff-tree --stdin' '
-       echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt
-       test $? = 1 && test $(wc -l <cnt) = 1
-'
-test_expect_success 'git diff-tree HEAD HEAD' '
-       git diff-tree --quiet HEAD HEAD >cnt
-       test $? = 0 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-files' '
-       git diff-files --quiet >cnt
-       test $? = 0 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-index --cached HEAD' '
-       git diff-index --quiet --cached HEAD >cnt
-       test $? = 0 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-index --cached HEAD^' '
-       git diff-index --quiet --cached HEAD^ >cnt
-       test $? = 1 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-index --cached HEAD^' '
-       echo text >>b &&
-       echo 3 >c &&
-       git add . && {
-               git diff-index --quiet --cached HEAD^ >cnt
-               test $? = 1 && test $(wc -l <cnt) = 0
-       }
-'
-test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' '
-       git commit -m "text in b" && {
-               git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt
-               test $? = 1 && test $(wc -l <cnt) = 0
-       }
-'
-test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' '
-       git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt
-       test $? = 0 && test $(wc -l <cnt) = 0
-'
-test_expect_success 'git diff-files' '
-       echo 3 >>c && {
-               git diff-files --quiet >cnt
-               test $? = 1 && test $(wc -l <cnt) = 0
-       }
-'
-test_expect_success 'git diff-index --cached HEAD' '
-       git update-index c && {
-               git diff-index --quiet --cached HEAD >cnt
-               test $? = 1 && test $(wc -l <cnt) = 0
-       }
-'
-
-test_done
diff --git a/t/t4021-format-patch-signer-mime.sh b/t/t4021-format-patch-signer-mime.sh
deleted file mode 100755 (executable)
index ba43f18..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-
-test_description='format-patch -s should force MIME encoding as needed'
-
-. ./test-lib.sh
-
-test_expect_success setup '
-
-       >F &&
-       git add F &&
-       git commit -m initial &&
-       echo new line >F &&
-
-       test_tick &&
-       git commit -m "This adds some lines to F" F
-
-'
-
-test_expect_success 'format normally' '
-
-       git format-patch --stdout -1 >output &&
-       ! grep Content-Type output
-
-'
-
-test_expect_success 'format with signoff without funny signer name' '
-
-       git format-patch -s --stdout -1 >output &&
-       ! grep Content-Type output
-
-'
-
-test_expect_success 'format with non ASCII signer name' '
-
-       GIT_COMMITTER_NAME="はまの ふにおう" \
-       git format-patch -s --stdout -1 >output &&
-       grep Content-Type output
-
-'
-
-test_expect_success 'attach and signoff do not duplicate mime headers' '
-
-       GIT_COMMITTER_NAME="はまの ふにおう" \
-       git format-patch -s --stdout -1 --attach >output &&
-       test `grep -ci ^MIME-Version: output` = 1
-
-'
-
-test_done
-
diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh
new file mode 100755 (executable)
index 0000000..e747e84
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+test_description='Return value of diffs'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       echo 1 >a &&
+       git add . &&
+       git commit -m first &&
+       echo 2 >b &&
+       git add . &&
+       git commit -a -m second
+'
+
+test_expect_success 'git diff-tree HEAD^ HEAD' '
+       git diff-tree --quiet HEAD^ HEAD >cnt
+       test $? = 1 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-tree HEAD^ HEAD -- a' '
+       git diff-tree --quiet HEAD^ HEAD -- a >cnt
+       test $? = 0 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-tree HEAD^ HEAD -- b' '
+       git diff-tree --quiet HEAD^ HEAD -- b >cnt
+       test $? = 1 && test $(wc -l <cnt) = 0
+'
+# this diff outputs one line: sha1 of the given head
+test_expect_success 'echo HEAD | git diff-tree --stdin' '
+       echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt
+       test $? = 1 && test $(wc -l <cnt) = 1
+'
+test_expect_success 'git diff-tree HEAD HEAD' '
+       git diff-tree --quiet HEAD HEAD >cnt
+       test $? = 0 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-files' '
+       git diff-files --quiet >cnt
+       test $? = 0 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-index --cached HEAD' '
+       git diff-index --quiet --cached HEAD >cnt
+       test $? = 0 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-index --cached HEAD^' '
+       git diff-index --quiet --cached HEAD^ >cnt
+       test $? = 1 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-index --cached HEAD^' '
+       echo text >>b &&
+       echo 3 >c &&
+       git add . && {
+               git diff-index --quiet --cached HEAD^ >cnt
+               test $? = 1 && test $(wc -l <cnt) = 0
+       }
+'
+test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' '
+       git commit -m "text in b" && {
+               git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt
+               test $? = 1 && test $(wc -l <cnt) = 0
+       }
+'
+test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' '
+       git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt
+       test $? = 0 && test $(wc -l <cnt) = 0
+'
+test_expect_success 'git diff-files' '
+       echo 3 >>c && {
+               git diff-files --quiet >cnt
+               test $? = 1 && test $(wc -l <cnt) = 0
+       }
+'
+test_expect_success 'git diff-index --cached HEAD' '
+       git update-index c && {
+               git diff-index --quiet --cached HEAD >cnt
+               test $? = 1 && test $(wc -l <cnt) = 0
+       }
+'
+
+test_done
diff --git a/t/t4036-format-patch-signer-mime.sh b/t/t4036-format-patch-signer-mime.sh
new file mode 100755 (executable)
index 0000000..ba43f18
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='format-patch -s should force MIME encoding as needed'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       >F &&
+       git add F &&
+       git commit -m initial &&
+       echo new line >F &&
+
+       test_tick &&
+       git commit -m "This adds some lines to F" F
+
+'
+
+test_expect_success 'format normally' '
+
+       git format-patch --stdout -1 >output &&
+       ! grep Content-Type output
+
+'
+
+test_expect_success 'format with signoff without funny signer name' '
+
+       git format-patch -s --stdout -1 >output &&
+       ! grep Content-Type output
+
+'
+
+test_expect_success 'format with non ASCII signer name' '
+
+       GIT_COMMITTER_NAME="はまの ふにおう" \
+       git format-patch -s --stdout -1 >output &&
+       grep Content-Type output
+
+'
+
+test_expect_success 'attach and signoff do not duplicate mime headers' '
+
+       GIT_COMMITTER_NAME="はまの ふにおう" \
+       git format-patch -s --stdout -1 --attach >output &&
+       test `grep -ci ^MIME-Version: output` = 1
+
+'
+
+test_done
+
diff --git a/t/t4203-patch-id.sh b/t/t4203-patch-id.sh
deleted file mode 100755 (executable)
index 04f7bae..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-test_description='git patch-id'
-
-. ./test-lib.sh
-
-test_expect_success 'setup' '
-       test_commit initial foo a &&
-       test_commit first foo b &&
-       git checkout -b same HEAD^ &&
-       test_commit same-msg foo b &&
-       git checkout -b notsame HEAD^ &&
-       test_commit notsame-msg foo c
-'
-
-test_expect_success 'patch-id output is well-formed' '
-       git log -p -1 | git patch-id > output &&
-       grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
-'
-
-get_patch_id () {
-       git log -p -1 "$1" | git patch-id |
-               sed "s# .*##" > patch-id_"$1"
-}
-
-test_expect_success 'patch-id detects equality' '
-       get_patch_id master &&
-       get_patch_id same &&
-       test_cmp patch-id_master patch-id_same
-'
-
-test_expect_success 'patch-id detects inequality' '
-       get_patch_id master &&
-       get_patch_id notsame &&
-       ! test_cmp patch-id_master patch-id_notsame
-'
-
-test_done
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
new file mode 100755 (executable)
index 0000000..04f7bae
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='git patch-id'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit initial foo a &&
+       test_commit first foo b &&
+       git checkout -b same HEAD^ &&
+       test_commit same-msg foo b &&
+       git checkout -b notsame HEAD^ &&
+       test_commit notsame-msg foo c
+'
+
+test_expect_success 'patch-id output is well-formed' '
+       git log -p -1 | git patch-id > output &&
+       grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
+'
+
+get_patch_id () {
+       git log -p -1 "$1" | git patch-id |
+               sed "s# .*##" > patch-id_"$1"
+}
+
+test_expect_success 'patch-id detects equality' '
+       get_patch_id master &&
+       get_patch_id same &&
+       test_cmp patch-id_master patch-id_same
+'
+
+test_expect_success 'patch-id detects inequality' '
+       get_patch_id master &&
+       get_patch_id notsame &&
+       ! test_cmp patch-id_master patch-id_notsame
+'
+
+test_done
index b7e362834bd743b61c27a4fd2118a83b14828489..7a84ab61d0de86798d84eaa9e1768688f6b5ad77 100755 (executable)
@@ -76,7 +76,7 @@ test_expect_success \
 
 test_expect_success \
     'git archive vs. git tar-tree' \
-    'diff b.tar b2.tar'
+    'test_cmp b.tar b2.tar'
 
 test_expect_success \
     'git archive in a bare repo' \
@@ -96,12 +96,12 @@ test_expect_success \
      "$TAR" xf b.tar -C extract a/a &&
      test-chmtime -v +0 extract/a/a |cut -f 1 >b.mtime &&
      echo "1117231200" >expected.mtime &&
-     diff expected.mtime b.mtime'
+     test_cmp expected.mtime b.mtime'
 
 test_expect_success \
     'git get-tar-commit-id' \
     'git get-tar-commit-id <b.tar >b.commitid &&
-     diff .git/$(git symbolic-ref HEAD) b.commitid'
+     test_cmp .git/$(git symbolic-ref HEAD) b.commitid'
 
 test_expect_success \
     'extract tar archive' \
@@ -110,7 +110,7 @@ test_expect_success \
 test_expect_success \
     'validate filenames' \
     '(cd b/a && find .) | sort >b.lst &&
-     diff a.lst b.lst'
+     test_cmp a.lst b.lst'
 
 test_expect_success \
     'validate file contents' \
@@ -127,7 +127,7 @@ test_expect_success \
 test_expect_success \
     'validate filenames with prefix' \
     '(cd c/prefix/a && find .) | sort >c.lst &&
-     diff a.lst c.lst'
+     test_cmp a.lst c.lst'
 
 test_expect_success \
     'validate file contents with prefix' \
@@ -148,8 +148,8 @@ test_expect_success \
      'validate substfile contents' \
      'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
       >f/a/substfile1.expected &&
-      diff f/a/substfile1.expected f/a/substfile1 &&
-      diff a/substfile2 f/a/substfile2
+      test_cmp f/a/substfile1.expected f/a/substfile1 &&
+      test_cmp a/substfile2 f/a/substfile2
 '
 
 test_expect_success \
@@ -160,8 +160,8 @@ test_expect_success \
      'validate substfile contents from archive with prefix' \
      'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
       >g/prefix/a/substfile1.expected &&
-      diff g/prefix/a/substfile1.expected g/prefix/a/substfile1 &&
-      diff a/substfile2 g/prefix/a/substfile2
+      test_cmp g/prefix/a/substfile1.expected g/prefix/a/substfile1 &&
+      test_cmp a/substfile2 g/prefix/a/substfile2
 '
 
 test_expect_success \
@@ -182,7 +182,7 @@ test_expect_success 'git archive --format=zip with --output' \
 
 $UNZIP -v >/dev/null 2>&1
 if [ $? -eq 127 ]; then
-       echo "Skipping ZIP tests, because unzip was not found"
+       say "Skipping ZIP tests, because unzip was not found"
        test_done
        exit
 fi
@@ -194,7 +194,7 @@ test_expect_success \
 test_expect_success \
     'validate filenames' \
     '(cd d/a && find .) | sort >d.lst &&
-     diff a.lst d.lst'
+     test_cmp a.lst d.lst'
 
 test_expect_success \
     'validate file contents' \
@@ -211,7 +211,7 @@ test_expect_success \
 test_expect_success \
     'validate filenames with prefix' \
     '(cd e/prefix/a && find .) | sort >e.lst &&
-     diff a.lst e.lst'
+     test_cmp a.lst e.lst'
 
 test_expect_success \
     'validate file contents with prefix' \
index ccfc64c6eef7e0aba7bd8a8496427470e9020309..e2aa254eae2ea930f29c4735f3f3d11bc790c455 100755 (executable)
@@ -13,11 +13,10 @@ TRASH=`pwd`
 test_expect_success \
     'setup' \
     'rm -f .git/index*
-     for i in a b c
-     do
-            dd if=/dev/zero bs=4k count=1 | perl -pe "y/\\000/$i/" >$i &&
-            git update-index --add $i || return 1
-     done &&
+     perl -e "print \"a\" x 4096;" > a &&
+     perl -e "print \"b\" x 4096;" > b &&
+     perl -e "print \"c\" x 4096;" > c &&
+     git update-index --add a b c &&
      cat c >d && echo foo >>d && git update-index --add d &&
      tree=`git write-tree` &&
      commit=`git commit-tree $tree </dev/null` && {
@@ -221,7 +220,7 @@ test_expect_success \
 test_expect_success \
     'verify-pack catches a corrupted pack signature' \
     'cat test-1-${packname_1}.pack >test-3.pack &&
-     dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 &&
+     echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=2 &&
      if git verify-pack test-3.idx
      then false
      else :;
@@ -230,7 +229,7 @@ test_expect_success \
 test_expect_success \
     'verify-pack catches a corrupted pack version' \
     'cat test-1-${packname_1}.pack >test-3.pack &&
-     dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 &&
+     echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=7 &&
      if git verify-pack test-3.idx
      then false
      else :;
@@ -239,7 +238,7 @@ test_expect_success \
 test_expect_success \
     'verify-pack catches a corrupted type/size of the 1st packed object data' \
     'cat test-1-${packname_1}.pack >test-3.pack &&
-     dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 &&
+     echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=12 &&
      if git verify-pack test-3.idx
      then false
      else :;
@@ -250,7 +249,7 @@ test_expect_success \
     'l=`wc -c <test-3.idx` &&
      l=`expr $l - 20` &&
      cat test-1-${packname_1}.pack >test-3.pack &&
-     dd if=/dev/zero of=test-3.idx count=20 bs=1 conv=notrunc seek=$l &&
+     printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l &&
      if git verify-pack test-3.pack
      then false
      else :;
index e6f70d474f2f855d3b2b40eed526e4873b3288d5..77982cdeacff246580993f03fedbc6dea4d25f0d 100755 (executable)
@@ -208,7 +208,7 @@ test_expect_success \
      obj=`git hash-object file_001` &&
      nr=`index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj` &&
      chmod +w ".git/objects/pack/pack-${pack1}.idx" &&
-     dd if=/dev/zero of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \
+     printf xxxx | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \
         bs=1 count=4 seek=$((8 + 256 * 4 + `wc -l <obj-list` * 20 + $nr * 4)) &&
      ( while read obj
        do git cat-file -p $obj >/dev/null || exit 1
index d4e30fc43c68ed9b0fc175f2a88a07de6458f58e..5132d4130968691bb115f5fc08cd0d2fd64ce669 100755 (executable)
@@ -55,6 +55,8 @@ do_corrupt_object() {
     test_must_fail git verify-pack ${pack}.pack
 }
 
+printf '\0' > zero
+
 test_expect_success \
     'initial setup validation' \
     'create_test_files &&
@@ -66,7 +68,7 @@ test_expect_success \
 
 test_expect_success \
     'create corruption in header of first object' \
-    'do_corrupt_object $blob_1 0 < /dev/zero &&
+    'do_corrupt_object $blob_1 0 < zero &&
      test_must_fail git cat-file blob $blob_1 > /dev/null &&
      test_must_fail git cat-file blob $blob_2 > /dev/null &&
      test_must_fail git cat-file blob $blob_3 > /dev/null'
@@ -125,7 +127,7 @@ test_expect_success \
     'create corruption in header of first delta' \
     'create_new_pack &&
      git prune-packed &&
-     do_corrupt_object $blob_2 0 < /dev/zero &&
+     do_corrupt_object $blob_2 0 < zero &&
      git cat-file blob $blob_1 > /dev/null &&
      test_must_fail git cat-file blob $blob_2 > /dev/null &&
      test_must_fail git cat-file blob $blob_3 > /dev/null'
@@ -180,7 +182,7 @@ test_expect_success \
     'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \
     'create_new_pack &&
      git prune-packed &&
-     do_corrupt_object $blob_2 2 < /dev/zero &&
+     do_corrupt_object $blob_2 2 < zero &&
      git cat-file blob $blob_1 > /dev/null &&
      test_must_fail git cat-file blob $blob_2 > /dev/null &&
      test_must_fail git cat-file blob $blob_3 > /dev/null'
@@ -207,7 +209,7 @@ test_expect_success \
     'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \
     'create_new_pack --delta-base-offset &&
      git prune-packed &&
-     do_corrupt_object $blob_2 2 < /dev/zero &&
+     do_corrupt_object $blob_2 2 < zero &&
      git cat-file blob $blob_1 > /dev/null &&
      test_must_fail git cat-file blob $blob_2 > /dev/null &&
      test_must_fail git cat-file blob $blob_3 > /dev/null'
@@ -259,7 +261,7 @@ test_expect_success \
 
 test_expect_success \
     '... and a redundant pack allows for full recovery too' \
-    'do_corrupt_object $blob_2 2 < /dev/zero &&
+    'do_corrupt_object $blob_2 2 < zero &&
      git cat-file blob $blob_1 > /dev/null &&
      test_must_fail git cat-file blob $blob_2 > /dev/null &&
      test_must_fail git cat-file blob $blob_3 > /dev/null &&
index 4fdb418550ee0f3c93e80f8c3df41094c0ada00c..5858b868ed6ff05d458996cf8c359a7148591582 100755 (executable)
@@ -71,6 +71,7 @@ test_expect_success 'post-checkout receives the right args when not switching br
         test $old = $new -a $flag = 0
 '
 
+if test "$(git config --bool core.filemode)" = true; then
 mkdir -p templates/hooks
 cat >templates/hooks/post-checkout <<'EOF'
 #!/bin/sh
@@ -82,5 +83,6 @@ test_expect_success 'post-checkout hook is triggered by clone' '
        git clone --template=templates . clone3 &&
        test -f clone3/.git/post-checkout.args
 '
+fi
 
 test_done
index eb637184a00007c61e6d92f7b5546eed6ec5a0ae..5ec668d6d8ac22f161549e5592a49bfdb0f11081 100755 (executable)
@@ -28,7 +28,7 @@ tokens_match () {
 }
 
 check_remote_track () {
-       actual=$(git remote show "$1" | sed -e '1,/Tracked/d') &&
+       actual=$(git remote show "$1" | sed -ne 's|^    \(.*\) tracked$|\1|p')
        shift &&
        tokens_match "$*" "$actual"
 }
@@ -136,47 +136,73 @@ EOF
 cat > test/expect << EOF
 * remote origin
   URL: $(pwd)/one
-  Remote branch merged with 'git pull' while on branch master
+  HEAD branch: master
+  Remote branches:
+    master new (next fetch will store in remotes/origin)
+    side   tracked
+  Local branches configured for 'git pull':
+    ahead    merges with remote master
+    master   merges with remote master
+    octopus  merges with remote topic-a
+                and with remote topic-b
+                and with remote topic-c
+    rebase  rebases onto remote master
+  Local refs configured for 'git push':
+    master pushes to master   (local out of date)
+    master pushes to upstream (create)
+* remote two
+  URL: ../two
+  HEAD branch (remote HEAD is ambiguous, may be one of the following):
+    another
     master
-  New remote branch (next fetch will store in remotes/origin)
-    master
-  Tracked remote branches
-    side
-    master
-  Local branches pushed with 'git push'
-    master:upstream
-    +refs/tags/lastbackup
+  Local refs configured for 'git push':
+    ahead  forces to master  (fast forwardable)
+    master pushes to another (up to date)
 EOF
 
 test_expect_success 'show' '
        (cd test &&
-        git config --add remote.origin.fetch \
-               refs/heads/master:refs/heads/upstream &&
+        git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
         git fetch &&
+        git checkout -b ahead origin/master &&
+        echo 1 >> file &&
+        test_tick &&
+        git commit -m update file &&
+        git checkout master &&
+        git branch --track octopus origin/master &&
+        git branch --track rebase origin/master &&
         git branch -d -r origin/master &&
+        git config --add remote.two.url ../two &&
+        git config branch.rebase.rebase true &&
+        git config branch.octopus.merge "topic-a topic-b topic-c" &&
         (cd ../one &&
          echo 1 > file &&
          test_tick &&
          git commit -m update file) &&
-        git config remote.origin.push \
-               refs/heads/master:refs/heads/upstream &&
-        git config --add remote.origin.push \
-               +refs/tags/lastbackup &&
-        git remote show origin > output &&
+        git config --add remote.origin.push : &&
+        git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
+        git config --add remote.origin.push +refs/tags/lastbackup &&
+        git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
+        git config --add remote.two.push refs/heads/master:refs/heads/another &&
+        git remote show origin two > output &&
+        git branch -d rebase octopus &&
         test_cmp expect output)
 '
 
 cat > test/expect << EOF
 * remote origin
   URL: $(pwd)/one
-  Remote branch merged with 'git pull' while on branch master
-    master
-  Tracked remote branches
+  HEAD branch: (not queried)
+  Remote branches: (status not queried)
     master
     side
-  Local branches pushed with 'git push'
-    master:upstream
-    +refs/tags/lastbackup
+  Local branches configured for 'git pull':
+    ahead  merges with remote master
+    master merges with remote master
+  Local refs configured for 'git push' (status not queried):
+    (matching)           pushes to (matching)
+    refs/heads/master    pushes to refs/heads/upstream
+    refs/tags/lastbackup forces to refs/tags/lastbackup
 EOF
 
 test_expect_success 'show -n' '
@@ -197,6 +223,46 @@ test_expect_success 'prune' '
         test_must_fail git rev-parse refs/remotes/origin/side)
 '
 
+test_expect_success 'set-head --delete' '
+       (cd test &&
+        git symbolic-ref refs/remotes/origin/HEAD &&
+        git remote set-head --delete origin &&
+        test_must_fail git symbolic-ref refs/remotes/origin/HEAD)
+'
+
+test_expect_success 'set-head --auto' '
+       (cd test &&
+        git remote set-head --auto origin &&
+        echo refs/remotes/origin/master >expect &&
+        git symbolic-ref refs/remotes/origin/HEAD >output &&
+        test_cmp expect output
+       )
+'
+
+cat >test/expect <<EOF
+error: Multiple remote HEAD branches. Please choose one explicitly with:
+  git remote set-head two another
+  git remote set-head two master
+EOF
+
+test_expect_success 'set-head --auto fails w/multiple HEADs' '
+       (cd test &&
+        test_must_fail git remote set-head --auto two >output 2>&1 &&
+       test_cmp expect output)
+'
+
+cat >test/expect <<EOF
+refs/remotes/origin/side2
+EOF
+
+test_expect_success 'set-head explicit' '
+       (cd test &&
+        git remote set-head origin side2 &&
+        git symbolic-ref refs/remotes/origin/HEAD >output &&
+        git remote set-head origin master &&
+        test_cmp expect output)
+'
+
 cat > test/expect << EOF
 Pruning origin
 URL: $(pwd)/one
@@ -343,7 +409,7 @@ test_expect_success '"remote show" does not show symbolic refs' '
        git clone one three &&
        (cd three &&
         git remote show origin > output &&
-        ! grep HEAD < output &&
+        ! grep "^ *HEAD$" < output &&
         ! grep -i stale < output)
 
 '
index 9e679b402dc826185377c431d353decd8a8a2bed..bee3424fed770aacac6dbcdf4ba58bfd7bf5c2da 100755 (executable)
@@ -191,38 +191,39 @@ test_expect_success 'bundle should be able to create a full history' '
 
 '
 
-test "$TEST_RSYNC" && {
+! rsync --help > /dev/null 2> /dev/null &&
+say 'Skipping rsync tests because rsync was not found' || {
 test_expect_success 'fetch via rsync' '
        git pack-refs &&
        mkdir rsynced &&
-       cd rsynced &&
-       git init &&
-       git fetch rsync://127.0.0.1$(pwd)/../.git master:refs/heads/master &&
-       git gc --prune &&
-       test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
-       git fsck --full
+       (cd rsynced &&
+        git init --bare &&
+        git fetch "rsync:$(pwd)/../.git" master:refs/heads/master &&
+        git gc --prune &&
+        test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
+        git fsck --full)
 '
 
 test_expect_success 'push via rsync' '
-       mkdir ../rsynced2 &&
-       (cd ../rsynced2 &&
+       mkdir rsynced2 &&
+       (cd rsynced2 &&
         git init) &&
-       git push rsync://127.0.0.1$(pwd)/../rsynced2/.git master &&
-       cd ../rsynced2 &&
-       git gc --prune &&
-       test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
-       git fsck --full
+       (cd rsynced &&
+        git push "rsync:$(pwd)/../rsynced2/.git" master) &&
+       (cd rsynced2 &&
+        git gc --prune &&
+        test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
+        git fsck --full)
 '
 
 test_expect_success 'push via rsync' '
-       cd .. &&
        mkdir rsynced3 &&
        (cd rsynced3 &&
         git init) &&
-       git push --all rsync://127.0.0.1$(pwd)/rsynced3/.git &&
-       cd rsynced3 &&
-       test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
-       git fsck --full
+       git push --all "rsync:$(pwd)/rsynced3/.git" &&
+       (cd rsynced3 &&
+        test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
+        git fsck --full)
 '
 }
 
index 22ba380034775e7584a33ca606294af34f568443..c28932216b1dd0893bc3c3a0a643963663ff8e1f 100755 (executable)
@@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me'
 test_refspec push ':refs/remotes/frotz/delete me'              invalid
 test_refspec fetch ':refs/remotes/frotz/HEAD to me'            invalid
 
+test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid
+test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid
+
+test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid
+test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid
+
+test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid
+test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid
+
+test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*'
+test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*'
+
 test_done
index 1f4608d8ba4748a2bd5c7a3d5a75a04364e8f646..dbb927dec8ea9f40e8e106f416c276f1b6a07868 100755 (executable)
@@ -129,8 +129,7 @@ do
        '' | '#'*) continue ;;
        esac
        test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'`
-       cnt=`expr $test_count + 1`
-       pfx=`printf "%04d" $cnt`
+       pfx=`printf "%04d" $test_count`
        expect_f="$TEST_DIRECTORY/t5515/fetch.$test"
        actual_f="$pfx-fetch.$test"
        expect_r="$TEST_DIRECTORY/t5515/refs.$test"
diff --git a/t/t5521-pull-symlink.sh b/t/t5521-pull-symlink.sh
deleted file mode 100755 (executable)
index 5672b51..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh
-
-test_description='pulling from symlinked subdir'
-
-. ./test-lib.sh
-
-# The scenario we are building:
-#
-#   trash\ directory/
-#     clone-repo/
-#       subdir/
-#         bar
-#     subdir-link -> clone-repo/subdir/
-#
-# The working directory is subdir-link.
-
-mkdir subdir
-echo file >subdir/file
-git add subdir/file
-git commit -q -m file
-git clone -q . clone-repo
-ln -s clone-repo/subdir/ subdir-link
-
-
-# Demonstrate that things work if we just avoid the symlink
-#
-test_expect_success 'pulling from real subdir' '
-       (
-               echo real >subdir/file &&
-               git commit -m real subdir/file &&
-               cd clone-repo/subdir/ &&
-               git pull &&
-               test real = $(cat file)
-       )
-'
-
-# From subdir-link, pulling should work as it does from
-# clone-repo/subdir/.
-#
-# Instead, the error pull gave was:
-#
-#   fatal: 'origin': unable to chdir or not a git archive
-#   fatal: The remote end hung up unexpectedly
-#
-# because git would find the .git/config for the "trash directory"
-# repo, not for the clone-repo repo.  The "trash directory" repo
-# had no entry for origin.  Git found the wrong .git because
-# git rev-parse --show-cdup printed a path relative to
-# clone-repo/subdir/, not subdir-link/.  Git rev-parse --show-cdup
-# used the correct .git, but when the git pull shell script did
-# "cd `git rev-parse --show-cdup`", it ended up in the wrong
-# directory.  A POSIX shell's "cd" works a little differently
-# than chdir() in C; "cd -P" is much closer to chdir().
-#
-test_expect_success 'pulling from symlinked subdir' '
-       (
-               echo link >subdir/file &&
-               git commit -m link subdir/file &&
-               cd subdir-link/ &&
-               git pull &&
-               test link = $(cat file)
-       )
-'
-
-# Prove that the remote end really is a repo, and other commands
-# work fine in this context.  It's just that "git pull" breaks.
-#
-test_expect_success 'pushing from symlinked subdir' '
-       (
-               cd subdir-link/ &&
-               echo push >file &&
-               git commit -m push ./file &&
-               git push
-       ) &&
-       test push = $(git show HEAD:subdir/file)
-'
-
-test_done
diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh
new file mode 100755 (executable)
index 0000000..5672b51
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+test_description='pulling from symlinked subdir'
+
+. ./test-lib.sh
+
+# The scenario we are building:
+#
+#   trash\ directory/
+#     clone-repo/
+#       subdir/
+#         bar
+#     subdir-link -> clone-repo/subdir/
+#
+# The working directory is subdir-link.
+
+mkdir subdir
+echo file >subdir/file
+git add subdir/file
+git commit -q -m file
+git clone -q . clone-repo
+ln -s clone-repo/subdir/ subdir-link
+
+
+# Demonstrate that things work if we just avoid the symlink
+#
+test_expect_success 'pulling from real subdir' '
+       (
+               echo real >subdir/file &&
+               git commit -m real subdir/file &&
+               cd clone-repo/subdir/ &&
+               git pull &&
+               test real = $(cat file)
+       )
+'
+
+# From subdir-link, pulling should work as it does from
+# clone-repo/subdir/.
+#
+# Instead, the error pull gave was:
+#
+#   fatal: 'origin': unable to chdir or not a git archive
+#   fatal: The remote end hung up unexpectedly
+#
+# because git would find the .git/config for the "trash directory"
+# repo, not for the clone-repo repo.  The "trash directory" repo
+# had no entry for origin.  Git found the wrong .git because
+# git rev-parse --show-cdup printed a path relative to
+# clone-repo/subdir/, not subdir-link/.  Git rev-parse --show-cdup
+# used the correct .git, but when the git pull shell script did
+# "cd `git rev-parse --show-cdup`", it ended up in the wrong
+# directory.  A POSIX shell's "cd" works a little differently
+# than chdir() in C; "cd -P" is much closer to chdir().
+#
+test_expect_success 'pulling from symlinked subdir' '
+       (
+               echo link >subdir/file &&
+               git commit -m link subdir/file &&
+               cd subdir-link/ &&
+               git pull &&
+               test link = $(cat file)
+       )
+'
+
+# Prove that the remote end really is a repo, and other commands
+# work fine in this context.  It's just that "git pull" breaks.
+#
+test_expect_success 'pushing from symlinked subdir' '
+       (
+               cd subdir-link/ &&
+               echo push >file &&
+               git commit -m push ./file &&
+               git push
+       ) &&
+       test push = $(git show HEAD:subdir/file)
+'
+
+test_done
index 10e5fd0d5a5c38eaa102d88e607f2585e1157526..c46592f03de2adfbb04f81ad2167e33a161d6d1b 100755 (executable)
@@ -11,6 +11,7 @@ This test runs various sanity checks on http-push.'
 
 ROOT_PATH="$PWD"
 LIB_HTTPD_DAV=t
+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5540'}
 
 if git http-push > /dev/null 2>&1 || [ $? -eq 128 ]
 then
@@ -20,13 +21,7 @@ then
 fi
 
 . "$TEST_DIRECTORY"/lib-httpd.sh
-
-if ! start_httpd >&3 2>&4
-then
-       say "skipping test, web server setup failed"
-       test_done
-       exit
-fi
+start_httpd
 
 test_expect_success 'setup remote repository' '
        cd "$ROOT_PATH" &&
diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh
new file mode 100755 (executable)
index 0000000..05b1b62
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='test fetching over http'
+. ./test-lib.sh
+
+if test -n "$NO_CURL"; then
+       say 'skipping test, git built without http support'
+       test_done
+fi
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
+start_httpd
+
+test_expect_success 'setup repository' '
+       echo content >file &&
+       git add file &&
+       git commit -m one
+'
+
+test_expect_success 'create http-accessible bare repository' '
+       mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+       (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+        git --bare init &&
+        echo "exec git update-server-info" >hooks/post-update &&
+        chmod +x hooks/post-update
+       ) &&
+       git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+       git push public master:master
+'
+
+test_expect_success 'clone http repository' '
+       git clone $HTTPD_URL/repo.git clone &&
+       test_cmp file clone/file
+'
+
+test_expect_success 'fetch changes via http' '
+       echo content >>file &&
+       git commit -a -m two &&
+       git push public
+       (cd clone && git pull) &&
+       test_cmp file clone/file
+'
+
+test_expect_success 'http remote detects correct HEAD' '
+       git push public master:other &&
+       (cd clone &&
+        git remote set-head origin -d &&
+        git remote set-head origin -a &&
+        git symbolic-ref refs/remotes/origin/HEAD > output &&
+        echo refs/remotes/origin/master > expect &&
+        test_cmp expect output
+       )
+'
+
+stop_httpd
+test_done
index 44793f2eee0e0c14802ecedfe0637cc6855f51b6..2335d8bc850b4b0010fcb9ac64a25d0c205e8a42 100755 (executable)
@@ -159,4 +159,19 @@ test_expect_success 'clone a void' '
        test_cmp target-6/.git/config target-7/.git/config
 '
 
+test_expect_success 'clone respects global branch.autosetuprebase' '
+       (
+               HOME=$(pwd) &&
+               export HOME &&
+               test_config="$HOME/.gitconfig" &&
+               unset GIT_CONFIG_NOGLOBAL &&
+               git config -f "$test_config" branch.autosetuprebase remote &&
+               rm -fr dst &&
+               git clone src dst &&
+               cd dst &&
+               actual="z$(git config branch.master.rebase)" &&
+               test ztrue = $actual
+       )
+'
+
 test_done
index 82b1d1e2b3f6704cf08540f0e6f4cecf0981cb7d..deffdaee490d620c44baaee143f11be604171a42 100755 (executable)
@@ -18,8 +18,8 @@ test_expect_success 'clone calls git upload-pack unqualified with no -u option'
 '
 
 test_expect_success 'clone calls specified git upload-pack with -u option' '
-       GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk
-       echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected
+       GIT_SSH=./not_ssh git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk
+       echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected
        test_cmp expected not_ssh_output
 '
 
diff --git a/t/t6023-merge-rename-nocruft.sh b/t/t6023-merge-rename-nocruft.sh
deleted file mode 100755 (executable)
index 65be95f..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/bin/sh
-
-test_description='Merge-recursive merging renames'
-. ./test-lib.sh
-
-test_expect_success setup \
-'
-cat >A <<\EOF &&
-a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-c cccccccccccccccccccccccccccccccccccccccccccccccc
-d dddddddddddddddddddddddddddddddddddddddddddddddd
-e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
-f ffffffffffffffffffffffffffffffffffffffffffffffff
-g gggggggggggggggggggggggggggggggggggggggggggggggg
-h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
-j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
-k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
-l llllllllllllllllllllllllllllllllllllllllllllllll
-m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
-n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
-o oooooooooooooooooooooooooooooooooooooooooooooooo
-EOF
-
-cat >M <<\EOF &&
-A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
-C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
-D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
-E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
-F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
-H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
-I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
-J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
-K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
-L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
-M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
-N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
-O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
-EOF
-
-git add A M &&
-git commit -m "initial has A and M" &&
-git branch white &&
-git branch red &&
-git branch blue &&
-
-git checkout white &&
-sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
-sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
-rm -f A M &&
-git update-index --add --remove A B M N &&
-git commit -m "white renames A->B, M->N" &&
-
-git checkout red &&
-echo created by red >R &&
-git update-index --add R &&
-git commit -m "red creates R" &&
-
-git checkout blue &&
-sed -e "/^o /s/.*/g : blue changes a line/" <A >B &&
-rm -f A &&
-mv B A &&
-git update-index A &&
-git commit -m "blue modify A" &&
-
-git checkout master'
-
-# This test broke in 65ac6e9c3f47807cb603af07a6a9e1a43bc119ae
-test_expect_success 'merge white into red (A->B,M->N)' \
-'
-       git checkout -b red-white red &&
-       git merge white &&
-       git write-tree >/dev/null || {
-               echo "BAD: merge did not complete"
-               return 1
-       }
-
-       test -f B || {
-               echo "BAD: B does not exist in working directory"
-               return 1
-       }
-       test -f N || {
-               echo "BAD: N does not exist in working directory"
-               return 1
-       }
-       test -f R || {
-               echo "BAD: R does not exist in working directory"
-               return 1
-       }
-
-       test -f A && {
-               echo "BAD: A still exists in working directory"
-               return 1
-       }
-       test -f M && {
-               echo "BAD: M still exists in working directory"
-               return 1
-       }
-       return 0
-'
-
-# This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9
-test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \
-'
-       git checkout -b white-blue white &&
-       echo dirty >A &&
-       git merge blue &&
-       git write-tree >/dev/null || {
-               echo "BAD: merge did not complete"
-               return 1
-       }
-
-       test -f A || {
-               echo "BAD: A does not exist in working directory"
-               return 1
-       }
-       test `cat A` = dirty || {
-               echo "BAD: A content is wrong"
-               return 1
-       }
-       test -f B || {
-               echo "BAD: B does not exist in working directory"
-               return 1
-       }
-       test -f N || {
-               echo "BAD: N does not exist in working directory"
-               return 1
-       }
-       test -f M && {
-               echo "BAD: M still exists in working directory"
-               return 1
-       }
-       return 0
-'
-
-test_done
index 8073e0c3efb2ac01e4a81e722fc357bcab13f5d4..41c6860be239a2abbab8b66ad8d4909b8913a9cc 100755 (executable)
@@ -3,9 +3,6 @@
 test_description='merge-recursive: handle file mode'
 . ./test-lib.sh
 
-# Note that we follow "chmod +x F" with "update-index --chmod=+x F" to
-# help filesystems that do not have the executable bit.
-
 test_expect_success 'mode change in one branch: keep changed version' '
        : >file1 &&
        git add file1 &&
@@ -15,8 +12,7 @@ test_expect_success 'mode change in one branch: keep changed version' '
        git add dummy &&
        git commit -m a &&
        git checkout -b b1 master &&
-       chmod +x file1 &&
-       git update-index --chmod=+x file1 &&
+       test_chmod +x file1 &&
        git commit -m b1 &&
        git checkout a1 &&
        git merge-recursive master -- a1 b1 &&
@@ -28,8 +24,7 @@ test_expect_success 'mode change in both branches: expect conflict' '
        git checkout -b a2 master &&
        : >file2 &&
        H=$(git hash-object file2) &&
-       chmod +x file2 &&
-       git update-index --add --chmod=+x file2 &&
+       test_chmod +x file2 &&
        git commit -m a2 &&
        git checkout -b b2 master &&
        : >file2 &&
diff --git a/t/t6034-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh
new file mode 100755 (executable)
index 0000000..65be95f
--- /dev/null
@@ -0,0 +1,139 @@
+#!/bin/sh
+
+test_description='Merge-recursive merging renames'
+. ./test-lib.sh
+
+test_expect_success setup \
+'
+cat >A <<\EOF &&
+a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+c cccccccccccccccccccccccccccccccccccccccccccccccc
+d dddddddddddddddddddddddddddddddddddddddddddddddd
+e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+f ffffffffffffffffffffffffffffffffffffffffffffffff
+g gggggggggggggggggggggggggggggggggggggggggggggggg
+h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
+k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+l llllllllllllllllllllllllllllllllllllllllllllllll
+m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+o oooooooooooooooooooooooooooooooooooooooooooooooo
+EOF
+
+cat >M <<\EOF &&
+A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
+C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
+F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
+I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
+J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
+K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
+L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
+M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
+O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
+EOF
+
+git add A M &&
+git commit -m "initial has A and M" &&
+git branch white &&
+git branch red &&
+git branch blue &&
+
+git checkout white &&
+sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
+sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
+rm -f A M &&
+git update-index --add --remove A B M N &&
+git commit -m "white renames A->B, M->N" &&
+
+git checkout red &&
+echo created by red >R &&
+git update-index --add R &&
+git commit -m "red creates R" &&
+
+git checkout blue &&
+sed -e "/^o /s/.*/g : blue changes a line/" <A >B &&
+rm -f A &&
+mv B A &&
+git update-index A &&
+git commit -m "blue modify A" &&
+
+git checkout master'
+
+# This test broke in 65ac6e9c3f47807cb603af07a6a9e1a43bc119ae
+test_expect_success 'merge white into red (A->B,M->N)' \
+'
+       git checkout -b red-white red &&
+       git merge white &&
+       git write-tree >/dev/null || {
+               echo "BAD: merge did not complete"
+               return 1
+       }
+
+       test -f B || {
+               echo "BAD: B does not exist in working directory"
+               return 1
+       }
+       test -f N || {
+               echo "BAD: N does not exist in working directory"
+               return 1
+       }
+       test -f R || {
+               echo "BAD: R does not exist in working directory"
+               return 1
+       }
+
+       test -f A && {
+               echo "BAD: A still exists in working directory"
+               return 1
+       }
+       test -f M && {
+               echo "BAD: M still exists in working directory"
+               return 1
+       }
+       return 0
+'
+
+# This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9
+test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \
+'
+       git checkout -b white-blue white &&
+       echo dirty >A &&
+       git merge blue &&
+       git write-tree >/dev/null || {
+               echo "BAD: merge did not complete"
+               return 1
+       }
+
+       test -f A || {
+               echo "BAD: A does not exist in working directory"
+               return 1
+       }
+       test `cat A` = dirty || {
+               echo "BAD: A content is wrong"
+               return 1
+       }
+       test -f B || {
+               echo "BAD: B does not exist in working directory"
+               return 1
+       }
+       test -f N || {
+               echo "BAD: N does not exist in working directory"
+               return 1
+       }
+       test -f M && {
+               echo "BAD: M still exists in working directory"
+               return 1
+       }
+       return 0
+'
+
+test_done
index 69501e2711f26a7c498d545520dcf47c00d9b1e1..1c27ffb45effdafaace54a29c3ce63f07d6899e6 100755 (executable)
@@ -185,8 +185,9 @@ cba
 EOF
 test_expect_success \
        'listing tags with substring as pattern must print those matching' '
-       git tag -l "*a*" > actual &&
-       test_cmp expect actual
+       rm *a* &&
+       git tag -l "*a*" > current &&
+       test_cmp expect current
 '
 
 cat >expect <<EOF
@@ -582,7 +583,7 @@ test_expect_success \
 # subsequent tests require gpg; check if it is available
 gpg --version >/dev/null
 if [ $? -eq 127 ]; then
-       echo "gpg not found - skipping tag signing and verification tests"
+       say "gpg not found - skipping tag signing and verification tests"
        test_done
        exit
 fi
@@ -614,7 +615,7 @@ test_expect_success \
 # that version, creation of signed tags using the generated key fails.
 case "$(gpg --version)" in
 'gpg (GnuPG) 1.0.6'*)
-       echo "Skipping signed tag tests, because a bug in 1.0.6 version"
+       say "Skipping signed tag tests, because a bug in 1.0.6 version"
        test_done
        exit
        ;;
index 2d919d69ef110408b820c76185d6b8da63ea183e..2f8404afbbc38e9bed17b1d3c9dde22ddcb2eaa2 100755 (executable)
@@ -87,30 +87,27 @@ do
        '
 done
 
+if ! echo 'echo space > "$1"' > "e space.sh"
+then
+       say "Skipping; FS does not support spaces in filenames"
+       test_done
+       exit
+fi
+
 test_expect_success 'editor with a space' '
 
-       if echo "echo space > \"\$1\"" > "e space.sh"
-       then
-               chmod a+x "e space.sh" &&
-               GIT_EDITOR="./e\ space.sh" git commit --amend &&
-               test space = "$(git show -s --pretty=format:%s)"
-       else
-               say "Skipping; FS does not support spaces in filenames"
-       fi
+       chmod a+x "e space.sh" &&
+       GIT_EDITOR="./e\ space.sh" git commit --amend &&
+       test space = "$(git show -s --pretty=format:%s)"
 
 '
 
 unset GIT_EDITOR
 test_expect_success 'core.editor with a space' '
 
-       if test -f "e space.sh"
-       then
-               git config core.editor \"./e\ space.sh\" &&
-               git commit --amend &&
-               test space = "$(git show -s --pretty=format:%s)"
-       else
-               say "Skipping; FS does not support spaces in filenames"
-       fi
+       git config core.editor \"./e\ space.sh\" &&
+       git commit --amend &&
+       test space = "$(git show -s --pretty=format:%s)"
 
 '
 
index 1636fac2a43e30a99674df98ff4544ee04612cc5..929d5d4d3b9d55f570cef1617a0716b17265c988 100755 (executable)
@@ -373,9 +373,9 @@ test_expect_success 'removal failure' '
 
        mkdir foo &&
        touch foo/bar &&
-       exec <foo/bar &&
-       chmod 0 foo &&
-       test_must_fail git clean -f -d
+       (exec <foo/bar &&
+        chmod 0 foo &&
+        test_must_fail git clean -f -d)
 
 '
 chmod 755 foo
diff --git a/t/t7502-status.sh b/t/t7502-status.sh
deleted file mode 100755 (executable)
index 93f875f..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2007 Johannes E. Schindelin
-#
-
-test_description='git status'
-
-. ./test-lib.sh
-
-test_expect_success 'setup' '
-       : > tracked &&
-       : > modified &&
-       mkdir dir1 &&
-       : > dir1/tracked &&
-       : > dir1/modified &&
-       mkdir dir2 &&
-       : > dir1/tracked &&
-       : > dir1/modified &&
-       git add . &&
-
-       git status >output &&
-
-       test_tick &&
-       git commit -m initial &&
-       : > untracked &&
-       : > dir1/untracked &&
-       : > dir2/untracked &&
-       echo 1 > dir1/modified &&
-       echo 2 > dir2/modified &&
-       echo 3 > dir2/added &&
-       git add dir2/added
-'
-
-test_expect_success 'status (1)' '
-
-       grep "use \"git rm --cached <file>\.\.\.\" to unstage" output
-
-'
-
-cat > expect << \EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-
-test_expect_success 'status (2)' '
-
-       git status > output &&
-       test_cmp expect output
-
-'
-
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files not listed (use -u option to show untracked files)
-EOF
-test_expect_success 'status -uno' '
-       mkdir dir3 &&
-       : > dir3/untracked1 &&
-       : > dir3/untracked2 &&
-       git status -uno >output &&
-       test_cmp expect output
-'
-
-test_expect_success 'status (status.showUntrackedFiles no)' '
-       git config status.showuntrackedfiles no
-       git status >output &&
-       test_cmp expect output
-'
-
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      dir3/
-#      expect
-#      output
-#      untracked
-EOF
-test_expect_success 'status -unormal' '
-       git status -unormal >output &&
-       test_cmp expect output
-'
-
-test_expect_success 'status (status.showUntrackedFiles normal)' '
-       git config status.showuntrackedfiles normal
-       git status >output &&
-       test_cmp expect output
-'
-
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      dir3/untracked1
-#      dir3/untracked2
-#      expect
-#      output
-#      untracked
-EOF
-test_expect_success 'status -uall' '
-       git status -uall >output &&
-       test_cmp expect output
-'
-test_expect_success 'status (status.showUntrackedFiles all)' '
-       git config status.showuntrackedfiles all
-       git status >output &&
-       rm -rf dir3 &&
-       git config --unset status.showuntrackedfiles &&
-       test_cmp expect output
-'
-
-cat > expect << \EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   ../dir2/added
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      untracked
-#      ../dir2/modified
-#      ../dir2/untracked
-#      ../expect
-#      ../output
-#      ../untracked
-EOF
-
-test_expect_success 'status with relative paths' '
-
-       (cd dir1 && git status) > output &&
-       test_cmp expect output
-
-'
-
-cat > expect << \EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-
-test_expect_success 'status without relative paths' '
-
-       git config status.relativePaths false
-       (cd dir1 && git status) > output &&
-       test_cmp expect output
-
-'
-
-cat <<EOF >expect
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/
-#      expect
-#      output
-#      untracked
-EOF
-test_expect_success 'status of partial commit excluding new file in index' '
-       git status dir1/modified >output &&
-       test_cmp expect output
-'
-
-test_expect_success 'setup status submodule summary' '
-       test_create_repo sm && (
-               cd sm &&
-               >foo &&
-               git add foo &&
-               git commit -m "Add foo"
-       ) &&
-       git add sm
-'
-
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#      new file:   sm
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-test_expect_success 'status submodule summary is disabled by default' '
-       git status >output &&
-       test_cmp expect output
-'
-
-# we expect the same as the previous test
-test_expect_success 'status --untracked-files=all does not show submodule' '
-       git status --untracked-files=all >output &&
-       test_cmp expect output
-'
-
-head=$(cd sm && git rev-parse --short=7 --verify HEAD)
-
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#      new file:   sm
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Modified submodules:
-#
-# * sm 0000000...$head (1):
-#   > Add foo
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-test_expect_success 'status submodule summary' '
-       git config status.submodulesummary 10 &&
-       git status >output &&
-       test_cmp expect output
-'
-
-
-cat >expect <<EOF
-# On branch master
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-no changes added to commit (use "git add" and/or "git commit -a")
-EOF
-test_expect_success 'status submodule summary (clean submodule)' '
-       git commit -m "commit submodule" &&
-       git config status.submodulesummary 10 &&
-       test_must_fail git status >output &&
-       test_cmp expect output
-'
-
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD^1 <file>..." to unstage)
-#
-#      new file:   dir2/added
-#      new file:   sm
-#
-# Changed but not updated:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Modified submodules:
-#
-# * sm 0000000...$head (1):
-#   > Add foo
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-test_expect_success 'status submodule summary (--amend)' '
-       git config status.submodulesummary 10 &&
-       git status --amend >output &&
-       test_cmp expect output
-'
-
-test_done
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
new file mode 100755 (executable)
index 0000000..93f875f
--- /dev/null
@@ -0,0 +1,400 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='git status'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       : > tracked &&
+       : > modified &&
+       mkdir dir1 &&
+       : > dir1/tracked &&
+       : > dir1/modified &&
+       mkdir dir2 &&
+       : > dir1/tracked &&
+       : > dir1/modified &&
+       git add . &&
+
+       git status >output &&
+
+       test_tick &&
+       git commit -m initial &&
+       : > untracked &&
+       : > dir1/untracked &&
+       : > dir2/untracked &&
+       echo 1 > dir1/modified &&
+       echo 2 > dir2/modified &&
+       echo 3 > dir2/added &&
+       git add dir2/added
+'
+
+test_expect_success 'status (1)' '
+
+       grep "use \"git rm --cached <file>\.\.\.\" to unstage" output
+
+'
+
+cat > expect << \EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+
+test_expect_success 'status (2)' '
+
+       git status > output &&
+       test_cmp expect output
+
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files not listed (use -u option to show untracked files)
+EOF
+test_expect_success 'status -uno' '
+       mkdir dir3 &&
+       : > dir3/untracked1 &&
+       : > dir3/untracked2 &&
+       git status -uno >output &&
+       test_cmp expect output
+'
+
+test_expect_success 'status (status.showUntrackedFiles no)' '
+       git config status.showuntrackedfiles no
+       git status >output &&
+       test_cmp expect output
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      dir3/
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status -unormal' '
+       git status -unormal >output &&
+       test_cmp expect output
+'
+
+test_expect_success 'status (status.showUntrackedFiles normal)' '
+       git config status.showuntrackedfiles normal
+       git status >output &&
+       test_cmp expect output
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      dir3/untracked1
+#      dir3/untracked2
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status -uall' '
+       git status -uall >output &&
+       test_cmp expect output
+'
+test_expect_success 'status (status.showUntrackedFiles all)' '
+       git config status.showuntrackedfiles all
+       git status >output &&
+       rm -rf dir3 &&
+       git config --unset status.showuntrackedfiles &&
+       test_cmp expect output
+'
+
+cat > expect << \EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   ../dir2/added
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      untracked
+#      ../dir2/modified
+#      ../dir2/untracked
+#      ../expect
+#      ../output
+#      ../untracked
+EOF
+
+test_expect_success 'status with relative paths' '
+
+       (cd dir1 && git status) > output &&
+       test_cmp expect output
+
+'
+
+cat > expect << \EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+
+test_expect_success 'status without relative paths' '
+
+       git config status.relativePaths false
+       (cd dir1 && git status) > output &&
+       test_cmp expect output
+
+'
+
+cat <<EOF >expect
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status of partial commit excluding new file in index' '
+       git status dir1/modified >output &&
+       test_cmp expect output
+'
+
+test_expect_success 'setup status submodule summary' '
+       test_create_repo sm && (
+               cd sm &&
+               >foo &&
+               git add foo &&
+               git commit -m "Add foo"
+       ) &&
+       git add sm
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#      new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status submodule summary is disabled by default' '
+       git status >output &&
+       test_cmp expect output
+'
+
+# we expect the same as the previous test
+test_expect_success 'status --untracked-files=all does not show submodule' '
+       git status --untracked-files=all >output &&
+       test_cmp expect output
+'
+
+head=$(cd sm && git rev-parse --short=7 --verify HEAD)
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#      new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Modified submodules:
+#
+# * sm 0000000...$head (1):
+#   > Add foo
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status submodule summary' '
+       git config status.submodulesummary 10 &&
+       git status >output &&
+       test_cmp expect output
+'
+
+
+cat >expect <<EOF
+# On branch master
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+test_expect_success 'status submodule summary (clean submodule)' '
+       git commit -m "commit submodule" &&
+       git config status.submodulesummary 10 &&
+       test_must_fail git status >output &&
+       test_cmp expect output
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD^1 <file>..." to unstage)
+#
+#      new file:   dir2/added
+#      new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#      modified:   dir1/modified
+#
+# Modified submodules:
+#
+# * sm 0000000...$head (1):
+#   > Add foo
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status submodule summary (--amend)' '
+       git config status.submodulesummary 10 &&
+       git status --amend >output &&
+       test_cmp expect output
+'
+
+test_done
index 08d5b91c9176bd9c6a23ffa72b2729bb1d2ba0d8..e426c96fb7d0f72b2822d4379b7fa671a04ab733 100755 (executable)
@@ -88,7 +88,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'Verify commandline' \
-    'diff commandline1 expected'
+    'test_cmp expected commandline1'
 
 cat >expected-show-all-headers <<\EOF
 0001-Second.patch
@@ -531,4 +531,15 @@ test_expect_success 'feed two files' '
        test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
 '
 
+test_expect_success 'in-reply-to but no threading' '
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --in-reply-to="<in-reply-id@example.com>" \
+               --no-thread \
+               $patches |
+       grep "In-Reply-To: <in-reply-id@example.com>"
+'
+
 test_done
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
deleted file mode 100755 (executable)
index fd18501..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2007 Eric Wong
-test_description='git svn dcommit clobber series'
-. ./lib-git-svn.sh
-
-test_expect_success 'initialize repo' '
-       mkdir import &&
-       cd import &&
-       awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
-       svn import -m "initial" . "$svnrepo" &&
-       cd .. &&
-       git svn init "$svnrepo" &&
-       git svn fetch &&
-       test -e file
-       '
-
-test_expect_success '(supposedly) non-conflicting change from SVN' '
-       test x"`sed -n -e 58p < file`" = x58 &&
-       test x"`sed -n -e 61p < file`" = x61 &&
-       svn co "$svnrepo" tmp &&
-       cd tmp &&
-               perl -i.bak -p -e "s/^58$/5588/" file &&
-               perl -i.bak -p -e "s/^61$/6611/" file &&
-               poke file &&
-               test x"`sed -n -e 58p < file`" = x5588 &&
-               test x"`sed -n -e 61p < file`" = x6611 &&
-               svn commit -m "58 => 5588, 61 => 6611" &&
-               cd ..
-       '
-
-test_expect_success 'some unrelated changes to git' "
-       echo hi > life &&
-       git update-index --add life &&
-       git commit -m hi-life &&
-       echo bye >> life &&
-       git commit -m bye-life life
-       "
-
-test_expect_success 'change file but in unrelated area' "
-       test x\"\`sed -n -e 4p < file\`\" = x4 &&
-       test x\"\`sed -n -e 7p < file\`\" = x7 &&
-       perl -i.bak -p -e 's/^4\$/4444/' file &&
-       perl -i.bak -p -e 's/^7\$/7777/' file &&
-       test x\"\`sed -n -e 4p < file\`\" = x4444 &&
-       test x\"\`sed -n -e 7p < file\`\" = x7777 &&
-       git commit -m '4 => 4444, 7 => 7777' file &&
-       git svn dcommit &&
-       svn up tmp &&
-       cd tmp &&
-               test x\"\`sed -n -e 4p < file\`\" = x4444 &&
-               test x\"\`sed -n -e 7p < file\`\" = x7777 &&
-               test x\"\`sed -n -e 58p < file\`\" = x5588 &&
-               test x\"\`sed -n -e 61p < file\`\" = x6611
-       "
-
-test_expect_success 'attempt to dcommit with a dirty index' '
-       echo foo >>file &&
-       git add file &&
-       test_must_fail git svn dcommit
-'
-
-test_done
diff --git a/t/t9108-git-svn-multi-glob.sh b/t/t9108-git-svn-multi-glob.sh
deleted file mode 100755 (executable)
index 8f79c3f..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2007 Eric Wong
-test_description='git svn globbing refspecs'
-. ./lib-git-svn.sh
-
-cat > expect.end <<EOF
-the end
-hi
-start a new branch
-initial
-EOF
-
-test_expect_success 'test refspec globbing' '
-       mkdir -p trunk/src/a trunk/src/b trunk/doc &&
-       echo "hello world" > trunk/src/a/readme &&
-       echo "goodbye world" > trunk/src/b/readme &&
-       svn import -m "initial" trunk "$svnrepo"/trunk &&
-       svn co "$svnrepo" tmp &&
-       (
-               cd tmp &&
-               mkdir branches branches/v1 tags &&
-               svn add branches tags &&
-               svn cp trunk branches/v1/start &&
-               svn commit -m "start a new branch" &&
-               svn up &&
-               echo "hi" >> branches/v1/start/src/b/readme &&
-               poke branches/v1/start/src/b/readme &&
-               echo "hey" >> branches/v1/start/src/a/readme &&
-               poke branches/v1/start/src/a/readme &&
-               svn commit -m "hi" &&
-               svn up &&
-               svn cp branches/v1/start tags/end &&
-               echo "bye" >> tags/end/src/b/readme &&
-               poke tags/end/src/b/readme &&
-               echo "aye" >> tags/end/src/a/readme &&
-               poke tags/end/src/a/readme &&
-               svn commit -m "the end" &&
-               echo "byebye" >> tags/end/src/b/readme &&
-               poke tags/end/src/b/readme &&
-               svn commit -m "nothing to see here"
-       ) &&
-       git config --add svn-remote.svn.url "$svnrepo" &&
-       git config --add svn-remote.svn.fetch \
-                        "trunk/src/a:refs/remotes/trunk" &&
-       git config --add svn-remote.svn.branches \
-                        "branches/*/*/src/a:refs/remotes/branches/*/*" &&
-       git config --add svn-remote.svn.tags\
-                        "tags/*/src/a:refs/remotes/tags/*" &&
-       git svn multi-fetch &&
-       git log --pretty=oneline refs/remotes/tags/end | \
-           sed -e "s/^.\{41\}//" > output.end &&
-       test_cmp expect.end output.end &&
-       test "`git rev-parse refs/remotes/tags/end~1`" = \
-               "`git rev-parse refs/remotes/branches/v1/start`" &&
-       test "`git rev-parse refs/remotes/branches/v1/start~2`" = \
-               "`git rev-parse refs/remotes/trunk`" &&
-       test_must_fail git rev-parse refs/remotes/tags/end@3
-       '
-
-echo try to try > expect.two
-echo nothing to see here >> expect.two
-cat expect.end >> expect.two
-
-test_expect_success 'test left-hand-side only globbing' '
-       git config --add svn-remote.two.url "$svnrepo" &&
-       git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
-       git config --add svn-remote.two.branches \
-                        "branches/*/*:refs/remotes/two/branches/*/*" &&
-       git config --add svn-remote.two.tags \
-                        "tags/*:refs/remotes/two/tags/*" &&
-       (
-               cd tmp &&
-               echo "try try" >> tags/end/src/b/readme &&
-               poke tags/end/src/b/readme &&
-               svn commit -m "try to try"
-       ) &&
-       git svn fetch two &&
-       test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
-       test `git rev-list refs/remotes/two/branches/v1/start | wc -l` -eq 3 &&
-       test `git rev-parse refs/remotes/two/branches/v1/start~2` = \
-            `git rev-parse refs/remotes/two/trunk` &&
-       test `git rev-parse refs/remotes/two/tags/end~3` = \
-            `git rev-parse refs/remotes/two/branches/v1/start` &&
-       git log --pretty=oneline refs/remotes/two/tags/end | \
-           sed -e "s/^.\{41\}//" > output.two &&
-       test_cmp expect.two output.two
-       '
-cat > expect.four <<EOF
-adios
-adding more
-Changed 2 in v2/start
-Another versioned branch
-initial
-EOF
-
-test_expect_success 'test another branch' '
-       (
-               cd tmp &&
-               mkdir branches/v2 &&
-               svn add branches/v2 &&
-               svn cp trunk branches/v2/start &&
-               svn commit -m "Another versioned branch" &&
-               svn up &&
-               echo "hello" >> branches/v2/start/src/b/readme &&
-               poke branches/v2/start/src/b/readme &&
-               echo "howdy" >> branches/v2/start/src/a/readme &&
-               poke branches/v2/start/src/a/readme &&
-               svn commit -m "Changed 2 in v2/start" &&
-               svn up &&
-               svn cp branches/v2/start tags/next &&
-               echo "bye" >> tags/next/src/b/readme &&
-               poke tags/next/src/b/readme &&
-               echo "aye" >> tags/next/src/a/readme &&
-               poke tags/next/src/a/readme &&
-               svn commit -m "adding more" &&
-               echo "byebye" >> tags/next/src/b/readme &&
-               poke tags/next/src/b/readme &&
-               svn commit -m "adios"
-       ) &&
-       git config --add svn-remote.four.url "$svnrepo" &&
-       git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk &&
-       git config --add svn-remote.four.branches \
-                        "branches/*/*:refs/remotes/four/branches/*/*" &&
-       git config --add svn-remote.four.tags \
-                        "tags/*:refs/remotes/four/tags/*" &&
-       git svn fetch four &&
-       test `git rev-list refs/remotes/four/tags/next | wc -l` -eq 5 &&
-       test `git rev-list refs/remotes/four/branches/v2/start | wc -l` -eq 3 &&
-       test `git rev-parse refs/remotes/four/branches/v2/start~2` = \
-            `git rev-parse refs/remotes/four/trunk` &&
-       test `git rev-parse refs/remotes/four/tags/next~2` = \
-            `git rev-parse refs/remotes/four/branches/v2/start` &&
-       git log --pretty=oneline refs/remotes/four/tags/next | \
-           sed -e "s/^.\{41\}//" > output.four &&
-       test_cmp expect.four output.four
-       '
-
-echo "Only one set of wildcard directories" \
-     "(e.g. '*' or '*/*/*') is supported: 'branches/*/t/*'" > expect.three
-echo "" >> expect.three
-
-test_expect_success 'test disallow multiple globs' '
-       git config --add svn-remote.three.url "$svnrepo" &&
-       git config --add svn-remote.three.fetch \
-                        trunk:refs/remotes/three/trunk &&
-       git config --add svn-remote.three.branches \
-                        "branches/*/t/*:refs/remotes/three/branches/*/*" &&
-       git config --add svn-remote.three.tags \
-                        "tags/*:refs/remotes/three/tags/*" &&
-       (
-               cd tmp &&
-               echo "try try" >> tags/end/src/b/readme &&
-               poke tags/end/src/b/readme &&
-               svn commit -m "try to try"
-       ) &&
-       test_must_fail git svn fetch three 2> stderr.three &&
-       test_cmp expect.three stderr.three
-       '
-
-test_done
diff --git a/t/t9109-git-svn-multi-glob.sh b/t/t9109-git-svn-multi-glob.sh
new file mode 100755 (executable)
index 0000000..8f79c3f
--- /dev/null
@@ -0,0 +1,160 @@
+#!/bin/sh
+# Copyright (c) 2007 Eric Wong
+test_description='git svn globbing refspecs'
+. ./lib-git-svn.sh
+
+cat > expect.end <<EOF
+the end
+hi
+start a new branch
+initial
+EOF
+
+test_expect_success 'test refspec globbing' '
+       mkdir -p trunk/src/a trunk/src/b trunk/doc &&
+       echo "hello world" > trunk/src/a/readme &&
+       echo "goodbye world" > trunk/src/b/readme &&
+       svn import -m "initial" trunk "$svnrepo"/trunk &&
+       svn co "$svnrepo" tmp &&
+       (
+               cd tmp &&
+               mkdir branches branches/v1 tags &&
+               svn add branches tags &&
+               svn cp trunk branches/v1/start &&
+               svn commit -m "start a new branch" &&
+               svn up &&
+               echo "hi" >> branches/v1/start/src/b/readme &&
+               poke branches/v1/start/src/b/readme &&
+               echo "hey" >> branches/v1/start/src/a/readme &&
+               poke branches/v1/start/src/a/readme &&
+               svn commit -m "hi" &&
+               svn up &&
+               svn cp branches/v1/start tags/end &&
+               echo "bye" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               echo "aye" >> tags/end/src/a/readme &&
+               poke tags/end/src/a/readme &&
+               svn commit -m "the end" &&
+               echo "byebye" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "nothing to see here"
+       ) &&
+       git config --add svn-remote.svn.url "$svnrepo" &&
+       git config --add svn-remote.svn.fetch \
+                        "trunk/src/a:refs/remotes/trunk" &&
+       git config --add svn-remote.svn.branches \
+                        "branches/*/*/src/a:refs/remotes/branches/*/*" &&
+       git config --add svn-remote.svn.tags\
+                        "tags/*/src/a:refs/remotes/tags/*" &&
+       git svn multi-fetch &&
+       git log --pretty=oneline refs/remotes/tags/end | \
+           sed -e "s/^.\{41\}//" > output.end &&
+       test_cmp expect.end output.end &&
+       test "`git rev-parse refs/remotes/tags/end~1`" = \
+               "`git rev-parse refs/remotes/branches/v1/start`" &&
+       test "`git rev-parse refs/remotes/branches/v1/start~2`" = \
+               "`git rev-parse refs/remotes/trunk`" &&
+       test_must_fail git rev-parse refs/remotes/tags/end@3
+       '
+
+echo try to try > expect.two
+echo nothing to see here >> expect.two
+cat expect.end >> expect.two
+
+test_expect_success 'test left-hand-side only globbing' '
+       git config --add svn-remote.two.url "$svnrepo" &&
+       git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
+       git config --add svn-remote.two.branches \
+                        "branches/*/*:refs/remotes/two/branches/*/*" &&
+       git config --add svn-remote.two.tags \
+                        "tags/*:refs/remotes/two/tags/*" &&
+       (
+               cd tmp &&
+               echo "try try" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "try to try"
+       ) &&
+       git svn fetch two &&
+       test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
+       test `git rev-list refs/remotes/two/branches/v1/start | wc -l` -eq 3 &&
+       test `git rev-parse refs/remotes/two/branches/v1/start~2` = \
+            `git rev-parse refs/remotes/two/trunk` &&
+       test `git rev-parse refs/remotes/two/tags/end~3` = \
+            `git rev-parse refs/remotes/two/branches/v1/start` &&
+       git log --pretty=oneline refs/remotes/two/tags/end | \
+           sed -e "s/^.\{41\}//" > output.two &&
+       test_cmp expect.two output.two
+       '
+cat > expect.four <<EOF
+adios
+adding more
+Changed 2 in v2/start
+Another versioned branch
+initial
+EOF
+
+test_expect_success 'test another branch' '
+       (
+               cd tmp &&
+               mkdir branches/v2 &&
+               svn add branches/v2 &&
+               svn cp trunk branches/v2/start &&
+               svn commit -m "Another versioned branch" &&
+               svn up &&
+               echo "hello" >> branches/v2/start/src/b/readme &&
+               poke branches/v2/start/src/b/readme &&
+               echo "howdy" >> branches/v2/start/src/a/readme &&
+               poke branches/v2/start/src/a/readme &&
+               svn commit -m "Changed 2 in v2/start" &&
+               svn up &&
+               svn cp branches/v2/start tags/next &&
+               echo "bye" >> tags/next/src/b/readme &&
+               poke tags/next/src/b/readme &&
+               echo "aye" >> tags/next/src/a/readme &&
+               poke tags/next/src/a/readme &&
+               svn commit -m "adding more" &&
+               echo "byebye" >> tags/next/src/b/readme &&
+               poke tags/next/src/b/readme &&
+               svn commit -m "adios"
+       ) &&
+       git config --add svn-remote.four.url "$svnrepo" &&
+       git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk &&
+       git config --add svn-remote.four.branches \
+                        "branches/*/*:refs/remotes/four/branches/*/*" &&
+       git config --add svn-remote.four.tags \
+                        "tags/*:refs/remotes/four/tags/*" &&
+       git svn fetch four &&
+       test `git rev-list refs/remotes/four/tags/next | wc -l` -eq 5 &&
+       test `git rev-list refs/remotes/four/branches/v2/start | wc -l` -eq 3 &&
+       test `git rev-parse refs/remotes/four/branches/v2/start~2` = \
+            `git rev-parse refs/remotes/four/trunk` &&
+       test `git rev-parse refs/remotes/four/tags/next~2` = \
+            `git rev-parse refs/remotes/four/branches/v2/start` &&
+       git log --pretty=oneline refs/remotes/four/tags/next | \
+           sed -e "s/^.\{41\}//" > output.four &&
+       test_cmp expect.four output.four
+       '
+
+echo "Only one set of wildcard directories" \
+     "(e.g. '*' or '*/*/*') is supported: 'branches/*/t/*'" > expect.three
+echo "" >> expect.three
+
+test_expect_success 'test disallow multiple globs' '
+       git config --add svn-remote.three.url "$svnrepo" &&
+       git config --add svn-remote.three.fetch \
+                        trunk:refs/remotes/three/trunk &&
+       git config --add svn-remote.three.branches \
+                        "branches/*/t/*:refs/remotes/three/branches/*/*" &&
+       git config --add svn-remote.three.tags \
+                        "tags/*:refs/remotes/three/tags/*" &&
+       (
+               cd tmp &&
+               echo "try try" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "try to try"
+       ) &&
+       test_must_fail git svn fetch three 2> stderr.three &&
+       test_cmp expect.three stderr.three
+       '
+
+test_done
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
new file mode 100755 (executable)
index 0000000..fd18501
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+test_description='git svn dcommit clobber series'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize repo' '
+       mkdir import &&
+       cd import &&
+       awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
+       svn import -m "initial" . "$svnrepo" &&
+       cd .. &&
+       git svn init "$svnrepo" &&
+       git svn fetch &&
+       test -e file
+       '
+
+test_expect_success '(supposedly) non-conflicting change from SVN' '
+       test x"`sed -n -e 58p < file`" = x58 &&
+       test x"`sed -n -e 61p < file`" = x61 &&
+       svn co "$svnrepo" tmp &&
+       cd tmp &&
+               perl -i.bak -p -e "s/^58$/5588/" file &&
+               perl -i.bak -p -e "s/^61$/6611/" file &&
+               poke file &&
+               test x"`sed -n -e 58p < file`" = x5588 &&
+               test x"`sed -n -e 61p < file`" = x6611 &&
+               svn commit -m "58 => 5588, 61 => 6611" &&
+               cd ..
+       '
+
+test_expect_success 'some unrelated changes to git' "
+       echo hi > life &&
+       git update-index --add life &&
+       git commit -m hi-life &&
+       echo bye >> life &&
+       git commit -m bye-life life
+       "
+
+test_expect_success 'change file but in unrelated area' "
+       test x\"\`sed -n -e 4p < file\`\" = x4 &&
+       test x\"\`sed -n -e 7p < file\`\" = x7 &&
+       perl -i.bak -p -e 's/^4\$/4444/' file &&
+       perl -i.bak -p -e 's/^7\$/7777/' file &&
+       test x\"\`sed -n -e 4p < file\`\" = x4444 &&
+       test x\"\`sed -n -e 7p < file\`\" = x7777 &&
+       git commit -m '4 => 4444, 7 => 7777' file &&
+       git svn dcommit &&
+       svn up tmp &&
+       cd tmp &&
+               test x\"\`sed -n -e 4p < file\`\" = x4444 &&
+               test x\"\`sed -n -e 7p < file\`\" = x7777 &&
+               test x\"\`sed -n -e 58p < file\`\" = x5588 &&
+               test x\"\`sed -n -e 61p < file\`\" = x6611
+       "
+
+test_expect_success 'attempt to dcommit with a dirty index' '
+       echo foo >>file &&
+       git add file &&
+       test_must_fail git svn dcommit
+'
+
+test_done
index 245a7c36628e955e04852a8c2beb75b8deaf4d7f..d28b71b8cf4bfefb987956be1d36203d69525677 100755 (executable)
@@ -9,7 +9,7 @@ test_description='Test export of commits to CVS'
 cvs >/dev/null 2>&1
 if test $? -ne 1
 then
-    test_expect_success 'skipping git cvsexportcommit tests, cvs not found' :
+    say 'skipping git cvsexportcommit tests, cvs not found'
     test_done
     exit
 fi
index 6a37f71d11800f92a117bfdcf38172bfc9000d77..466240cd415fe544ed55d991e176129e7f869b79 100755 (executable)
@@ -13,12 +13,12 @@ cvs CLI client via git-cvsserver server'
 cvs >/dev/null 2>&1
 if test $? -ne 1
 then
-    test_expect_success 'skipping git-cvsserver tests, cvs not found' :
+    say 'skipping git-cvsserver tests, cvs not found'
     test_done
     exit
 fi
 perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
-    test_expect_success 'skipping git-cvsserver tests, Perl SQLite interface unavailable' :
+    say 'skipping git-cvsserver tests, Perl SQLite interface unavailable'
     test_done
     exit
 }
@@ -44,7 +44,7 @@ test_expect_success 'setup' '
   git add secondrootfile &&
   git commit -m "second root") &&
   git pull secondroot master &&
-  git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
+  git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
   GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
   GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log"
 '
@@ -267,7 +267,7 @@ test_expect_success 'gitcvs.ext.dbname' \
 
 rm -fr "$SERVERDIR"
 cd "$WORKDIR" &&
-git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
+git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
 GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
 exit 1
index e27a1c5f85bbecac652ce8d224f8fc5e99b02a4e..888223013444999817a93082418fb60690a425e3 100755 (executable)
@@ -49,12 +49,12 @@ not_present() {
 cvs >/dev/null 2>&1
 if test $? -ne 1
 then
-    test_expect_success 'skipping git-cvsserver tests, cvs not found' :
+    say 'skipping git-cvsserver tests, cvs not found'
     test_done
     exit
 fi
 perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
-    test_expect_success 'skipping git-cvsserver tests, Perl SQLite interface unavailable' :
+    say 'skipping git-cvsserver tests, Perl SQLite interface unavailable'
     test_done
     exit
 }
@@ -84,7 +84,7 @@ test_expect_success 'setup' '
     echo "subdir/file.h crlf" >> .gitattributes &&
     git add .gitattributes textfile.c binfile.bin mixedUp.c subdir/* &&
     git commit -q -m "First Commit" &&
-    git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
+    git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
     GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
     GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log"
 '
index 6ed10d0933daa493e7a32296b38e9a32a23a725a..dce06bcc9733f010463692cc2f41400d5a518106 100755 (executable)
@@ -63,18 +63,10 @@ gitweb_run () {
        # gitweb.log is left for debugging
 }
 
-safe_chmod () {
-       chmod "$1" "$2" &&
-       if [ "$(git config --get core.filemode)" = false ]
-       then
-               git update-index --chmod="$1" "$2"
-       fi
-}
-
 . ./test-lib.sh
 
 perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
-    test_expect_success 'skipping gitweb tests, perl version is too old' :
+    say 'skipping gitweb tests, perl version is too old'
     test_done
     exit
 }
@@ -242,7 +234,7 @@ test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): mode change' \
-       'safe_chmod +x new_file &&
+       'test_chmod +x new_file &&
         git commit -a -m "Mode changed." &&
         gitweb_run "p=.git;a=commitdiff"'
 test_debug 'cat gitweb.log'
@@ -281,7 +273,7 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'commitdiff(0): mode change and modified' \
        'echo "New line" >> file2 &&
-        safe_chmod +x file2 &&
+        test_chmod +x file2 &&
         git commit -a -m "Mode change and modification." &&
         gitweb_run "p=.git;a=commitdiff"'
 test_debug 'cat gitweb.log'
@@ -308,7 +300,7 @@ test_expect_success \
        'commitdiff(0): renamed, mode change and modified' \
        'git mv file3 file2 &&
         echo "Propter nomen suum." >> file2 &&
-        safe_chmod +x file2 &&
+        test_chmod +x file2 &&
         git commit -a -m "File rename, mode change and modification." &&
         gitweb_run "p=.git;a=commitdiff"'
 test_debug 'cat gitweb.log'
@@ -425,10 +417,10 @@ test_expect_success \
         git add 03-new &&
         git mv 04-rename-from 04-rename-to &&
         echo "Changed" >> 04-rename-to &&
-        safe_chmod +x 05-mode-change &&
+        test_chmod +x 05-mode-change &&
         rm -f 06-file-or-symlink && ln -s 01-change 06-file-or-symlink &&
         echo "Changed and have mode changed" > 07-change-mode-change   &&
-        safe_chmod +x 07-change-mode-change &&
+        test_chmod +x 07-change-mode-change &&
         git commit -a -m "Large commit" &&
         git checkout master'
 
index b81d5dfc340e050815ad9b2fd0d0636c529ce8d3..4a501c68471e3ba472bf82d65789d06838c7eec8 100755 (executable)
@@ -7,7 +7,7 @@ test_description='perl interface (Git.pm)'
 . ./test-lib.sh
 
 perl -MTest::More -e 0 2>/dev/null || {
-       say_color skip "Perl Test::More unavailable, skipping test"
+       say "Perl Test::More unavailable, skipping test"
        test_done
 }
 
index 7a847ecbde018f36911ee6a1074ba169af1f350d..638cca41e3bb08da342a5ed115a0d1f779f63fbb 100644 (file)
@@ -238,18 +238,25 @@ test_merge () {
        git tag "$1"
 }
 
+# This function helps systems where core.filemode=false is set.
+# Use it instead of plain 'chmod +x' to set or unset the executable bit
+# of a file in the working directory and add it to the index.
+
+test_chmod () {
+       chmod "$@" &&
+       git update-index --add "--chmod=$@"
+}
+
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
 
 test_ok_ () {
-       test_count=$(expr "$test_count" + 1)
-       test_success=$(expr "$test_success" + 1)
+       test_success=$(($test_success + 1))
        say_color "" "  ok $test_count: $@"
 }
 
 test_failure_ () {
-       test_count=$(expr "$test_count" + 1)
-       test_failure=$(expr "$test_failure" + 1);
+       test_failure=$(($test_failure + 1))
        say_color error "FAIL $test_count: $1"
        shift
        echo "$@" | sed -e 's/^/        /'
@@ -257,13 +264,11 @@ test_failure_ () {
 }
 
 test_known_broken_ok_ () {
-       test_count=$(expr "$test_count" + 1)
        test_fixed=$(($test_fixed+1))
        say_color "" "  FIXED $test_count: $@"
 }
 
 test_known_broken_failure_ () {
-       test_count=$(expr "$test_count" + 1)
        test_broken=$(($test_broken+1))
        say_color skip "  still broken $test_count: $@"
 }
@@ -279,12 +284,11 @@ test_run_ () {
 }
 
 test_skip () {
-       this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
-       this_test="$this_test.$(expr "$test_count" + 1)"
+       test_count=$(($test_count+1))
        to_skip=
        for skp in $GIT_SKIP_TESTS
        do
-               case "$this_test" in
+               case $this_test.$test_count in
                $skp)
                        to_skip=t
                esac
@@ -292,7 +296,6 @@ test_skip () {
        case "$to_skip" in
        t)
                say_color skip >&3 "skipping test: $@"
-               test_count=$(expr "$test_count" + 1)
                say_color skip "skip $test_count: $1"
                : true
                ;;
@@ -370,7 +373,7 @@ test_external () {
        then
                # Announce the script to reduce confusion about the
                # test output that follows.
-               say_color "" " run $(expr "$test_count" + 1): $descr ($*)"
+               say_color "" " run $test_count: $descr ($*)"
                # Run command; redirect its stderr to &4 as in
                # test_run_, but keep its stdout on our stdout even in
                # non-verbose mode.
@@ -464,7 +467,7 @@ test_done () {
        trap - EXIT
        test_results_dir="$TEST_DIRECTORY/test-results"
        mkdir -p "$test_results_dir"
-       test_results_path="$test_results_dir/${0%-*}-$$"
+       test_results_path="$test_results_dir/${0%.sh}-$$"
 
        echo "total $test_count" >> $test_results_path
        echo "success $test_success" >> $test_results_path
@@ -613,7 +616,8 @@ test_create_repo "$test"
 # in subprocesses like git equals our $PWD (for pathname comparisons).
 cd -P "$test" || exit 1
 
-this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
+this_test=${0##*/}
+this_test=${this_test%%-*}
 for skp in $GIT_SKIP_TESTS
 do
        to_skip=
index 9ad4a16c317b90770974aa5afbcf0986f4a5db91..9ae92cd39c3f45cb2a58a24801a790ce6622d22c 100644 (file)
@@ -138,6 +138,11 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
        }
 }
 
+static const char *rsync_url(const char *url)
+{
+       return prefixcmp(url, "rsync://") ? skip_prefix(url, "rsync:") : url;
+}
+
 static struct ref *get_refs_via_rsync(struct transport *transport)
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
@@ -153,7 +158,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport)
                die ("Could not make temporary directory");
        temp_dir_len = temp_dir.len;
 
-       strbuf_addstr(&buf, transport->url);
+       strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addstr(&buf, "/refs");
 
        memset(&rsync, 0, sizeof(rsync));
@@ -169,7 +174,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport)
                die ("Could not run rsync to get refs");
 
        strbuf_reset(&buf);
-       strbuf_addstr(&buf, transport->url);
+       strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addstr(&buf, "/packed-refs");
 
        args[2] = buf.buf;
@@ -206,7 +211,7 @@ static int fetch_objs_via_rsync(struct transport *transport,
        const char *args[8];
        int result;
 
-       strbuf_addstr(&buf, transport->url);
+       strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addstr(&buf, "/objects/");
 
        memset(&rsync, 0, sizeof(rsync));
@@ -285,7 +290,7 @@ static int rsync_transport_push(struct transport *transport,
 
        /* first push the objects */
 
-       strbuf_addstr(&buf, transport->url);
+       strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addch(&buf, '/');
 
        memset(&rsync, 0, sizeof(rsync));
@@ -306,7 +311,8 @@ static int rsync_transport_push(struct transport *transport,
        args[i++] = NULL;
 
        if (run_command(&rsync))
-               return error("Could not push objects to %s", transport->url);
+               return error("Could not push objects to %s",
+                               rsync_url(transport->url));
 
        /* copy the refs to the temporary directory; they could be packed. */
 
@@ -327,10 +333,11 @@ static int rsync_transport_push(struct transport *transport,
        if (!(flags & TRANSPORT_PUSH_FORCE))
                args[i++] = "--ignore-existing";
        args[i++] = temp_dir.buf;
-       args[i++] = transport->url;
+       args[i++] = rsync_url(transport->url);
        args[i++] = NULL;
        if (run_command(&rsync))
-               result = error("Could not push to %s", transport->url);
+               result = error("Could not push to %s",
+                               rsync_url(transport->url));
 
        if (remove_dir_recursively(&temp_dir, 0))
                warning ("Could not remove temporary directory %s.",
@@ -723,7 +730,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
        ret->remote = remote;
        ret->url = url;
 
-       if (!prefixcmp(url, "rsync://")) {
+       if (!prefixcmp(url, "rsync:")) {
                ret->get_refs_list = get_refs_via_rsync;
                ret->fetch = fetch_objs_via_rsync;
                ret->push = rsync_transport_push;
index e547282ed5c0027b35cbbd8e4f07bf968c6f2171..86e28650b887b4fcc1b05cc4d3102367df18a9ac 100644 (file)
@@ -49,39 +49,20 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
        memcpy(new, ce, size);
        new->next = NULL;
        new->ce_flags = (new->ce_flags & ~clear) | set;
-       add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK);
+       add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 }
 
-/* Unlink the last component and attempt to remove leading
- * directories, in case this unlink is the removal of the
- * last entry in the directory -- empty directories are removed.
+/*
+ * Unlink the last component and schedule the leading directories for
+ * removal, such that empty directories get removed.
  */
 static void unlink_entry(struct cache_entry *ce)
 {
-       char *cp, *prev;
-       char *name = ce->name;
-
-       if (has_symlink_or_noent_leading_path(ce_namelen(ce), ce->name))
+       if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
                return;
-       if (unlink(name))
+       if (unlink(ce->name))
                return;
-       prev = NULL;
-       while (1) {
-               int status;
-               cp = strrchr(name, '/');
-               if (prev)
-                       *prev = '/';
-               if (!cp)
-                       break;
-
-               *cp = 0;
-               status = rmdir(name);
-               if (status) {
-                       *cp = '/';
-                       break;
-               }
-               prev = cp;
-       }
+       schedule_dir_for_removal(ce->name, ce_namelen(ce));
 }
 
 static struct checkout state;
@@ -112,11 +93,10 @@ static int check_updates(struct unpack_trees_options *o)
                        display_progress(progress, ++cnt);
                        if (o->update)
                                unlink_entry(ce);
-                       remove_index_entry_at(&o->result, i);
-                       i--;
-                       continue;
                }
        }
+       remove_marked_cache_entries(&o->result);
+       remove_scheduled_dirs();
 
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
@@ -286,9 +266,9 @@ static int unpack_nondirectories(int n, unsigned long mask,
        if (o->merge)
                return call_unpack_fn(src, o);
 
-       n += o->merge;
        for (i = 0; i < n; i++)
-               add_entry(o, src[i], 0, 0);
+               if (src[i] && src[i] != o->df_conflict_entry)
+                       add_entry(o, src[i], 0, 0);
        return 0;
 }
 
@@ -380,8 +360,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
        memset(&o->result, 0, sizeof(o->result));
        o->result.initialized = 1;
-       if (o->src_index)
-               o->result.timestamp = o->src_index->timestamp;
+       if (o->src_index) {
+               o->result.timestamp.sec = o->src_index->timestamp.sec;
+               o->result.timestamp.nsec = o->src_index->timestamp.nsec;
+       }
        o->merge_size = len;
 
        if (!dfc)
@@ -446,7 +428,7 @@ static int verify_uptodate(struct cache_entry *ce,
 {
        struct stat st;
 
-       if (o->index_only || o->reset)
+       if (o->index_only || o->reset || ce_uptodate(ce))
                return 0;
 
        if (!lstat(ce->name, &st)) {
@@ -583,7 +565,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
        if (o->index_only || o->reset || !o->update)
                return 0;
 
-       if (has_symlink_or_noent_leading_path(ce_namelen(ce), ce->name))
+       if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
                return 0;
 
        if (!lstat(ce->name, &st)) {
index 3e97462bdd2ed72b4ec60a1eb3869e516609867b..02184d9cde2e27d14c8c2845d7e2c4eb7f0c9b09 100644 (file)
@@ -293,15 +293,14 @@ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
                for (; off1 < lim1; off1++)
                        rchg1[rindex1[off1]] = 1;
        } else {
-               long ec;
                xdpsplit_t spl;
                spl.i1 = spl.i2 = 0;
 
                /*
                 * Divide ...
                 */
-               if ((ec = xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb,
-                                   need_min, &spl, xenv)) < 0) {
+               if (xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb,
+                             need_min, &spl, xenv) < 0) {
 
                        return -1;
                }
index 05bfa41f102801a5182e7fc642976f91e9ba7db6..c4bedf0d1ce1252563d7f36da7d846f5943343b0 100644 (file)
@@ -132,7 +132,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
        if (xecfg->flags & XDL_EMIT_COMMON)
                return xdl_emit_common(xe, xscr, ecb, xecfg);
 
-       for (xch = xche = xscr; xch; xch = xche->next) {
+       for (xch = xscr; xch; xch = xche->next) {
                xche = xdl_get_hunk(xch, xecfg);
 
                s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);