Merge branch 'jc/commit-s-subject-is-not-a-footer'
authorJunio C Hamano <gitster@pobox.com>
Sat, 7 Nov 2009 07:17:47 +0000 (23:17 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 7 Nov 2009 07:17:47 +0000 (23:17 -0800)
* jc/commit-s-subject-is-not-a-footer:
builtin-commit.c: fix logic to omit empty line before existing footers

53 files changed:
Documentation/Makefile
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/git-bisect.txt
Documentation/git-check-ref-format.txt
Documentation/git-describe.txt
Documentation/git-fetch.txt
Documentation/git-merge.txt
Documentation/git-pull.txt
Documentation/git-stash.txt
Documentation/manpage-quote-apos.xsl [new file with mode: 0644]
Documentation/merge-options.txt
Documentation/pretty-formats.txt
Makefile
archive.c
builtin-branch.c
builtin-check-ref-format.c
builtin-checkout.c
builtin-clone.c
builtin-commit.c
builtin-help.c
builtin-log.c
builtin-ls-remote.c
builtin-merge.c
builtin-pack-objects.c
builtin-push.c
builtin-rev-list.c
builtin-shortlog.c
builtin-show-branch.c
cache.h
commit.c
commit.h
compat/bswap.h
contrib/buildsystems/Generators/Vcproj.pm
diff.c
diff.h
git-bisect.sh
git-rebase--interactive.sh
git-stash.sh
log-tree.c
pretty.c
reflog-walk.c
reflog-walk.h
remote-curl.c
setup.c
submodule.c [new file with mode: 0644]
submodule.h [new file with mode: 0644]
t/t1402-check-ref-format.sh [new file with mode: 0755]
t/t4041-diff-submodule.sh [new file with mode: 0755]
t/t6006-rev-list-format.sh
t/t9150-svk-mergetickets.sh [changed mode: 0644->0755]
t/t9151-svn-mergeinfo.sh [changed mode: 0644->0755]
transport.c
index 06b0c57b95057b3df4f215f3191fd8e9fc473e6f..cd5b4396dbc174edbba3eb42bb285eefc57f9caf 100644 (file)
@@ -103,6 +103,14 @@ ifdef DOCBOOK_SUPPRESS_SP
 XMLTO_EXTRA += -m manpage-suppress-sp.xsl
 endif
 
+# If your target system uses GNU groff, it may try to render
+# apostrophes as a "pretty" apostrophe using unicode.  This breaks
+# cut&paste, so you should set GNU_ROFF to force them to be ASCII
+# apostrophes.  Unfortunately does not work with non-GNU roff.
+ifdef GNU_ROFF
+XMLTO_EXTRA += -m manpage-quote-apos.xsl
+endif
+
 SHELL_PATH ?= $(SHELL)
 # Shell quote;
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
index 9276faeb11aec2650393c56fe5edf2b571692dbd..e26b84706f8f29de26036ceec691e8cd6aac4661 100644 (file)
@@ -87,6 +87,13 @@ endif::git-format-patch[]
        Show only names and status of changed files. See the description
        of the `--diff-filter` option on what the status letters mean.
 
+--submodule[=<format>]::
+       Chose the output format for submodule differences. <format> can be one of
+       'short' and 'log'. 'short' just shows pairs of commit names, this format
+       is used when this option is not given. 'log' is the default value for this
+       option and lists the commits in that commit range like the 'summary'
+       option of linkgit:git-submodule[1] does.
+
 --color::
        Show colored diff.
 
index 5eb2b0ee07b2f4e81e909a103f486c1a6d2dc6cb..28868747dac778dd1c527f3e40446edd739a5ba9 100644 (file)
@@ -1,25 +1,13 @@
-ifndef::git-pull[]
--q::
---quiet::
-       Pass --quiet to git-fetch-pack and silence any other internally
-       used git commands.
-
--v::
---verbose::
-       Be verbose.
-endif::git-pull[]
-
 -a::
 --append::
        Append ref names and object names of fetched refs to the
        existing contents of `.git/FETCH_HEAD`.  Without this
        option old data in `.git/FETCH_HEAD` will be overwritten.
 
---upload-pack <upload-pack>::
-       When given, and the repository to fetch from is handled
-       by 'git-fetch-pack', '--exec=<upload-pack>' is passed to
-       the command to specify non-default path for the command
-       run on the other end.
+--depth=<depth>::
+       Deepen the history of a 'shallow' repository created by
+       `git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
+       by the specified number of commits.
 
 -f::
 --force::
@@ -29,6 +17,10 @@ endif::git-pull[]
        fetches is a descendant of `<lbranch>`.  This option
        overrides that check.
 
+-k::
+--keep::
+       Keep downloaded pack.
+
 ifdef::git-pull[]
 --no-tags::
 endif::git-pull[]
@@ -49,10 +41,6 @@ endif::git-pull[]
        flag lets all tags and their associated objects be
        downloaded.
 
--k::
---keep::
-       Keep downloaded pack.
-
 -u::
 --update-head-ok::
        By default 'git-fetch' refuses to update the head which
@@ -62,7 +50,19 @@ endif::git-pull[]
        implementing your own Porcelain you are not supposed to
        use it.
 
---depth=<depth>::
-       Deepen the history of a 'shallow' repository created by
-       `git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
-       by the specified number of commits.
+--upload-pack <upload-pack>::
+       When given, and the repository to fetch from is handled
+       by 'git-fetch-pack', '--exec=<upload-pack>' is passed to
+       the command to specify non-default path for the command
+       run on the other end.
+
+ifndef::git-pull[]
+-q::
+--quiet::
+       Pass --quiet to git-fetch-pack and silence any other internally
+       used git commands.
+
+-v::
+--verbose::
+       Be verbose.
+endif::git-pull[]
index 63e7a42cb353e2cd0c8bbb6e83927bd1863a32cb..d2ffae0c10176a412202d381a9c7beb2b21979ef 100644 (file)
@@ -20,7 +20,7 @@ on the subcommand:
  git bisect bad [<rev>]
  git bisect good [<rev>...]
  git bisect skip [(<rev>|<range>)...]
- git bisect reset [<branch>]
+ git bisect reset [<commit>]
  git bisect visualize
  git bisect replay <logfile>
  git bisect log
@@ -81,16 +81,27 @@ will have been left with the first bad kernel revision in "refs/bisect/bad".
 Bisect reset
 ~~~~~~~~~~~~
 
-To return to the original head after a bisect session, issue the
-following command:
+After a bisect session, to clean up the bisection state and return to
+the original HEAD, issue the following command:
 
 ------------------------------------------------
 $ git bisect reset
 ------------------------------------------------
 
-This resets the tree to the original branch instead of being on the
-bisection commit ("git bisect start" will also do that, as it resets
-the bisection state).
+By default, this will return your tree to the commit that was checked
+out before `git bisect start`.  (A new `git bisect start` will also do
+that, as it cleans up the old bisection state.)
+
+With an optional argument, you can return to a different commit
+instead:
+
+------------------------------------------------
+$ git bisect reset <commit>
+------------------------------------------------
+
+For example, `git bisect reset HEAD` will leave you on the current
+bisection commit and avoid switching commits at all, while `git bisect
+reset bisect/bad` will check out the first bad revision.
 
 Bisect visualize
 ~~~~~~~~~~~~~~~~
index e9b3b40af497c7b8508e31e171bf87e565b96963..0aeef24780f07e5d5fa021f6ebdaa7090a3dcdb7 100644 (file)
@@ -9,6 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git check-ref-format' <refname>
+'git check-ref-format' --print <refname>
 'git check-ref-format' --branch <branchname-shorthand>
 
 DESCRIPTION
@@ -63,19 +64,31 @@ reference name expressions (see linkgit:git-rev-parse[1]):
 
 . at-open-brace `@{` is used as a notation to access a reflog entry.
 
+With the `--print` option, if 'refname' is acceptable, it prints the
+canonicalized name of a hypothetical reference with that name.  That is,
+it prints 'refname' with any extra `/` characters removed.
+
 With the `--branch` option, it expands the ``previous branch syntax''
 `@{-n}`.  For example, `@{-1}` is a way to refer the last branch you
 were on.  This option should be used by porcelains to accept this
 syntax anywhere a branch name is expected, so they can act as if you
 typed the branch name.
 
-EXAMPLE
--------
-
-git check-ref-format --branch @{-1}::
-
-Print the name of the previous branch.
+EXAMPLES
+--------
 
+* Print the name of the previous branch:
++
+------------
+$ git check-ref-format --branch @{-1}
+------------
+
+* Determine the reference name to use for a new branch:
++
+------------
+$ ref=$(git check-ref-format --print "refs/heads/$newbranch") ||
+die "we do not like '$newbranch' as a branch name."
+------------
 
 GIT
 ---
index b231dbb947791bb4fc5cde552e8c736b3558ca0a..2f979167819f0e4500b998b41092e18ef053cead 100644 (file)
@@ -44,7 +44,9 @@ OPTIONS
 
 --abbrev=<n>::
        Instead of using the default 7 hexadecimal digits as the
-       abbreviated object name, use <n> digits.
+       abbreviated object name, use <n> digits, or as many digits
+       as needed to form a unique object name.  An <n> of 0
+       will suppress long format, only showing the closest tag.
 
 --candidates=<n>::
        Instead of considering only the 10 most recent tags as
@@ -68,8 +70,8 @@ OPTIONS
        This is useful when you want to see parts of the commit object name
        in "describe" output, even when the commit in question happens to be
        a tagged version.  Instead of just emitting the tag name, it will
-       describe such a commit as v1.2-0-deadbeef (0th commit since tag v1.2
-       that points at object deadbeef....).
+       describe such a commit as v1.2-0-gdeadbee (0th commit since tag v1.2
+       that points at object deadbee....).
 
 --match <pattern>::
        Only consider tags matching the given pattern (can be used to avoid
@@ -108,7 +110,7 @@ the output shows the reference path as well:
        [torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
        tags/v1.0.0-21-g975b
 
-       [torvalds@g5 git]$ git describe --all HEAD^
+       [torvalds@g5 git]$ git describe --all --abbrev=4 HEAD^
        heads/lt/describe-7-g975b
 
 With --abbrev set to 0, the command can be used to find the
@@ -117,6 +119,13 @@ closest tagname without any suffix:
        [torvalds@g5 git]$ git describe --abbrev=0 v1.0.5^2
        tags/v1.0.0
 
+Note that the suffix you get if you type these commands today may be
+longer than what Linus saw above when he ran these commands, as your
+git repository may have new commits whose object names begin with
+975b that did not exist back then, and "-g975b" suffix alone may not
+be sufficient to disambiguate these commits.
+
+
 SEARCH STRATEGY
 ---------------
 
index d3164c5c88db6b9e02a4186c398e19c425bc204b..f2483d624ead24031ef3cf320a0c151cc6f6cb2b 100644 (file)
@@ -37,6 +37,35 @@ include::pull-fetch-param.txt[]
 
 include::urls-remotes.txt[]
 
+
+EXAMPLES
+--------
+
+* Update the remote-tracking branches:
++
+------------------------------------------------
+$ git fetch origin
+------------------------------------------------
++
+The above command copies all branches from the remote refs/heads/
+namespace and stores them to the local refs/remotes/origin/ namespace,
+unless the branch.<name>.fetch option is used to specify a non-default
+refspec.
+
+* Using refspecs explicitly:
++
+------------------------------------------------
+$ git fetch origin +pu:pu maint:tmp
+------------------------------------------------
++
+This updates (or creates, as necessary) branches `pu` and `tmp` in
+the local repository by fetching from the branches (respectively)
+`pu` and `maint` from the remote repository.
++
+The `pu` branch will be updated even if it is does not fast-forward,
+because it is prefixed with a plus sign; `tmp` will not be.
+
+
 SEE ALSO
 --------
 linkgit:git-pull[1]
index d05f324462d23f64ba9563666e555a9eee3c443f..e886c2ef543501deea84909b2e88fb163a1c9d2b 100644 (file)
@@ -212,6 +212,39 @@ You can work through the conflict with a number of tools:
    common ancestor, 'git show :2:filename' shows the HEAD
    version and 'git show :3:filename' shows the remote version.
 
+
+EXAMPLES
+--------
+
+* Merge branches `fixes` and `enhancements` on top of
+  the current branch, making an octopus merge:
++
+------------------------------------------------
+$ git merge fixes enhancements
+------------------------------------------------
+
+* Merge branch `obsolete` into the current branch, using `ours`
+  merge strategy:
++
+------------------------------------------------
+$ git merge -s ours obsolete
+------------------------------------------------
+
+* Merge branch `maint` into the current branch, but do not make
+  a new commit automatically:
++
+------------------------------------------------
+$ git merge --no-commit maint
+------------------------------------------------
++
+This can be used when you want to include further changes to the
+merge, or want to write your own merge commit message.
++
+You should refrain from abusing this option to sneak substantial
+changes into a merge commit.  Small fixups like bumping
+release/version name would be acceptable.
+
+
 SEE ALSO
 --------
 linkgit:git-fmt-merge-msg[1], linkgit:git-pull[1],
index 7578623edba9e2ddc5232f1a981bcb297182638d..b93201158fa6fda914b6093af5911b7884328838 100644 (file)
@@ -26,6 +26,10 @@ Also note that options meant for 'git-pull' itself and underlying
 
 OPTIONS
 -------
+
+Options related to merging
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 include::merge-options.txt[]
 
 :git-pull: 1
@@ -47,6 +51,9 @@ unless you have read linkgit:git-rebase[1] carefully.
 --no-rebase::
        Override earlier --rebase.
 
+Options related to fetching
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 include::fetch-options.txt[]
 
 include::pull-fetch-param.txt[]
@@ -131,54 +138,13 @@ $ git pull origin next
 ------------------------------------------------
 +
 This leaves a copy of `next` temporarily in FETCH_HEAD, but
-does not update any remote-tracking branches.
-
-* Bundle local branch `fixes` and `enhancements` on top of
-  the current branch, making an Octopus merge:
-+
-------------------------------------------------
-$ git pull . fixes enhancements
-------------------------------------------------
-+
-This `git pull .` syntax is equivalent to `git merge`.
-
-* Merge local branch `obsolete` into the current branch, using `ours`
-  merge strategy:
-+
-------------------------------------------------
-$ git pull -s ours . obsolete
-------------------------------------------------
-
-* Merge local branch `maint` into the current branch, but do not make
-  a commit automatically:
+does not update any remote-tracking branches. Using remote-tracking
+branches, the same can be done by invoking fetch and merge:
 +
 ------------------------------------------------
-$ git pull --no-commit . maint
+$ git fetch origin
+$ git merge origin/next
 ------------------------------------------------
-+
-This can be used when you want to include further changes to the
-merge, or want to write your own merge commit message.
-+
-You should refrain from abusing this option to sneak substantial
-changes into a merge commit.  Small fixups like bumping
-release/version name would be acceptable.
-
-* Command line pull of multiple branches from one repository:
-+
-------------------------------------------------
-$ git checkout master
-$ git fetch origin +pu:pu maint:tmp
-$ git pull . tmp
-------------------------------------------------
-+
-This updates (or creates, as necessary) branches `pu` and `tmp` in
-the local repository by fetching from the branches (respectively)
-`pu` and `maint` from the remote repository.
-+
-The `pu` branch will be updated even if it is does not fast-forward;
-the others will not be.
-+
-The final command then merges the newly fetched `tmp` into master.
 
 
 If you tried a pull which resulted in a complex conflicts and
index fafe728f890d5020ffc5f1ab28deb4b3d02313a5..3f14b727b899fbf3b4f7cb6513bd1b14e5938160 100644 (file)
@@ -78,8 +78,7 @@ stash@{1}: On master: 9cc0589... Add git-stash
 ----------------------------------------------------------------
 +
 The command takes options applicable to the 'git-log'
-command to control what is shown and how. If no options are set, the
-default is `-n 10`. See linkgit:git-log[1].
+command to control what is shown and how. See linkgit:git-log[1].
 
 show [<stash>]::
 
diff --git a/Documentation/manpage-quote-apos.xsl b/Documentation/manpage-quote-apos.xsl
new file mode 100644 (file)
index 0000000..aeb8839
--- /dev/null
@@ -0,0 +1,16 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+               version="1.0">
+
+<!-- work around newer groff/man setups using a prettier apostrophe
+     that unfortunately does not quote anything when cut&pasting
+     examples to the shell -->
+<xsl:template name="escape.apostrophe">
+  <xsl:param name="content"/>
+  <xsl:call-template name="string.subst">
+    <xsl:with-param name="string" select="$content"/>
+    <xsl:with-param name="target">'</xsl:with-param>
+    <xsl:with-param name="replacement">\(aq</xsl:with-param>
+  </xsl:call-template>
+</xsl:template>
+
+</xsl:stylesheet>
index adadf8e4bf309a2fd2ec8efbeff09b410ca7b041..48d04a5d8833a2c83f1dc754c798688b194de5b9 100644 (file)
@@ -1,43 +1,42 @@
--q::
---quiet::
-       Operate quietly.
-
--v::
---verbose::
-       Be verbose.
-
---stat::
-       Show a diffstat at the end of the merge. The diffstat is also
-       controlled by the configuration option merge.stat.
-
--n::
---no-stat::
-       Do not show a diffstat at the end of the merge.
+--commit::
+--no-commit::
+       Perform the merge and commit the result. This option can
+       be used to override --no-commit.
++
+With --no-commit perform the merge but pretend the merge
+failed and do not autocommit, to give the user a chance to
+inspect and further tweak the merge result before committing.
 
---summary::
---no-summary::
-       Synonyms to --stat and --no-stat; these are deprecated and will be
-       removed in the future.
+--ff::
+--no-ff::
+       Do not generate a merge commit if the merge resolved as
+       a fast-forward, only update the branch pointer. This is
+       the default behavior of git-merge.
++
+With --no-ff Generate a merge commit even if the merge
+resolved as a fast-forward.
 
 --log::
+--no-log::
        In addition to branch names, populate the log message with
        one-line descriptions from the actual commits that are being
        merged.
++
+With --no-log do not list one-line descriptions from the
+actual commits being merged.
 
---no-log::
-       Do not list one-line descriptions from the actual commits being
-       merged.
-
---no-commit::
-       Perform the merge but pretend the merge failed and do
-       not autocommit, to give the user a chance to inspect and
-       further tweak the merge result before committing.
 
---commit::
-       Perform the merge and commit the result. This option can
-       be used to override --no-commit.
+--stat::
+-n::
+--no-stat::
+       Show a diffstat at the end of the merge. The diffstat is also
+       controlled by the configuration option merge.stat.
++
+With -n or --no-stat do not show a diffstat at the end of the
+merge.
 
 --squash::
+--no-squash::
        Produce the working tree and index state as if a real
        merge happened (except for the merge information),
        but do not actually make a commit or
        commit.  This allows you to create a single commit on
        top of the current branch whose effect is the same as
        merging another branch (or more in case of an octopus).
-
---no-squash::
-       Perform the merge and commit the result. This option can
-       be used to override --squash.
-
---no-ff::
-       Generate a merge commit even if the merge resolved as a
-       fast-forward.
-
---ff::
-       Do not generate a merge commit if the merge resolved as
-       a fast-forward, only update the branch pointer. This is
-       the default behavior of git-merge.
++
+With --no-squash perform the merge and commit the result. This
+option can be used to override --squash.
 
 -s <strategy>::
 --strategy=<strategy>::
        If there is no `-s` option, a built-in list of strategies
        is used instead ('git-merge-recursive' when merging a single
        head, 'git-merge-octopus' otherwise).
+
+--summary::
+--no-summary::
+       Synonyms to --stat and --no-stat; these are deprecated and will be
+       removed in the future.
+
+-q::
+--quiet::
+       Operate quietly.
+
+-v::
+--verbose::
+       Be verbose.
index 2a845b1e57590a6f18f05fd3efa858b736c1071a..38b9904791466152a98ab3df7c5b84ac66dbac73 100644 (file)
@@ -123,6 +123,9 @@ The placeholders are:
 - '%s': subject
 - '%f': sanitized subject line, suitable for a filename
 - '%b': body
+- '%gD': reflog selector, e.g., `refs/stash@\{1\}`
+- '%gd': shortened reflog selector, e.g., `stash@\{1\}`
+- '%gs': reflog subject
 - '%Cred': switch color to red
 - '%Cgreen': switch color to green
 - '%Cblue': switch color to blue
@@ -132,6 +135,12 @@ The placeholders are:
 - '%n': newline
 - '%x00': print a byte from a hex code
 
+NOTE: Some placeholders may depend on other options given to the
+revision traversal engine. For example, the `%g*` reflog options will
+insert an empty string unless we are traversing reflog entries (e.g., by
+`git log -g`). The `%d` placeholder will use the "short" decoration
+format if `--decorate` was not already provided on the command line.
+
 * 'tformat:'
 +
 The 'tformat:' format works exactly like 'format:', except that it
index 42b7d60e195559c8c0a7c6b32ce3b7ab8cfacebd..5d5976f94faa1b981f5c8ad9056ab4c5cc9dd3a6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -159,6 +159,10 @@ all::
 # Define ASCIIDOC_NO_ROFF if your DocBook XSL escapes raw roff directives
 # (versions 1.72 and later and 1.68.1 and earlier).
 #
+# Define GNU_ROFF if your target system uses GNU groff.  This forces
+# apostrophes to be ASCII so that cut&pasting examples to the shell
+# will work.
+#
 # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
 # MakeMaker (e.g. using ActiveState under Cygwin).
 #
@@ -412,6 +416,7 @@ LIB_H += builtin.h
 LIB_H += cache.h
 LIB_H += cache-tree.h
 LIB_H += commit.h
+LIB_H += compat/bswap.h
 LIB_H += compat/cygwin.h
 LIB_H += compat/mingw.h
 LIB_H += csum-file.h
@@ -452,6 +457,7 @@ LIB_H += sideband.h
 LIB_H += sigchain.h
 LIB_H += strbuf.h
 LIB_H += string-list.h
+LIB_H += submodule.h
 LIB_H += tag.h
 LIB_H += transport.h
 LIB_H += tree.h
@@ -550,6 +556,7 @@ LIB_OBJS += sideband.o
 LIB_OBJS += sigchain.o
 LIB_OBJS += strbuf.o
 LIB_OBJS += string-list.o
+LIB_OBJS += submodule.o
 LIB_OBJS += symlinks.o
 LIB_OBJS += tag.o
 LIB_OBJS += trace.o
@@ -1375,7 +1382,7 @@ SHELL = $(SHELL_PATH)
 
 all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
 ifneq (,$X)
-       $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
+       $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
 endif
 
 all::
index 0cc79d2a240ac260fec66e6c30e28b438bcb5948..55b273246e006ad55c51d3e5cb6bed3153ae8cf4 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -31,6 +31,8 @@ static void format_subst(const struct commit *commit,
 {
        char *to_free = NULL;
        struct strbuf fmt = STRBUF_INIT;
+       struct pretty_print_context ctx = {0};
+       ctx.date_mode = DATE_NORMAL;
 
        if (src == buf->buf)
                to_free = strbuf_detach(buf, NULL);
@@ -48,7 +50,7 @@ static void format_subst(const struct commit *commit,
                strbuf_add(&fmt, b + 8, c - b - 8);
 
                strbuf_add(buf, src, b - src);
-               format_commit_message(commit, fmt.buf, buf, DATE_NORMAL);
+               format_commit_message(commit, fmt.buf, buf, &ctx);
                len -= c + 1 - src;
                src  = c + 1;
        }
index 9f57992062314a3d8d168b5cfb6b3c6737605033..05e876e28554fec546ee4256bf3576dcb8017047 100644 (file)
@@ -387,8 +387,9 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 
                commit = item->commit;
                if (commit && !parse_commit(commit)) {
+                       struct pretty_print_context ctx = {0};
                        pretty_print_commit(CMIT_FMT_ONELINE, commit,
-                                           &subject, 0, NULL, NULL, 0, 0);
+                                           &subject, &ctx);
                        sub = subject.buf;
                }
 
index f9381e07eaeda673e91ef6250eca4027c5ba0278..e3e7bdf52f0b1f597e6cfd3affcf75f41f183d75 100644 (file)
@@ -7,6 +7,28 @@
 #include "builtin.h"
 #include "strbuf.h"
 
+/*
+ * Replace each run of adjacent slashes in src with a single slash,
+ * and write the result to dst.
+ *
+ * This function is similar to normalize_path_copy(), but stripped down
+ * to meet check_ref_format's simpler needs.
+ */
+static void collapse_slashes(char *dst, const char *src)
+{
+       char ch;
+       char prev = '\0';
+
+       while ((ch = *src++) != '\0') {
+               if (prev == '/' && ch == prev)
+                       continue;
+
+               *dst++ = ch;
+               prev = ch;
+       }
+       *dst = '\0';
+}
+
 int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
 {
        if (argc == 3 && !strcmp(argv[1], "--branch")) {
@@ -17,6 +39,15 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
                printf("%s\n", sb.buf + 11);
                exit(0);
        }
+       if (argc == 3 && !strcmp(argv[1], "--print")) {
+               char *refname = xmalloc(strlen(argv[2]) + 1);
+
+               if (check_ref_format(argv[2]))
+                       exit(1);
+               collapse_slashes(refname, argv[2]);
+               printf("%s\n", refname);
+               exit(0);
+       }
        if (argc != 2)
                usage("git check-ref-format refname");
        return !!check_ref_format(argv[1]);
index d050c3789fcdaf1b50c12a20c28cbeaf774048eb..64f3a11ae1d415c466def8eccefe9dbc5b6b3926 100644 (file)
@@ -302,8 +302,9 @@ static void show_local_changes(struct object *head)
 static void describe_detached_head(char *msg, struct commit *commit)
 {
        struct strbuf sb = STRBUF_INIT;
+       struct pretty_print_context ctx = {0};
        parse_commit(commit);
-       pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, 0, NULL, NULL, 0, 0);
+       pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, &ctx);
        fprintf(stderr, "%s %s... %s\n", msg,
                find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), sb.buf);
        strbuf_release(&sb);
@@ -572,6 +573,40 @@ static int interactive_checkout(const char *revision, const char **pathspec,
        return run_add_interactive(revision, "--patch=checkout", pathspec);
 }
 
+struct tracking_name_data {
+       const char *name;
+       char *remote;
+       int unique;
+};
+
+static int check_tracking_name(const char *refname, const unsigned char *sha1,
+                              int flags, void *cb_data)
+{
+       struct tracking_name_data *cb = cb_data;
+       const char *slash;
+
+       if (prefixcmp(refname, "refs/remotes/"))
+               return 0;
+       slash = strchr(refname + 13, '/');
+       if (!slash || strcmp(slash + 1, cb->name))
+               return 0;
+       if (cb->remote) {
+               cb->unique = 0;
+               return 0;
+       }
+       cb->remote = xstrdup(refname);
+       return 0;
+}
+
+static const char *unique_tracking_name(const char *name)
+{
+       struct tracking_name_data cb_data = { name, NULL, 1 };
+       for_each_ref(check_tracking_name, &cb_data);
+       if (cb_data.unique)
+               return cb_data.remote;
+       free(cb_data.remote);
+       return NULL;
+}
 
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
@@ -582,6 +617,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        struct tree *source_tree = NULL;
        char *conflict_style = NULL;
        int patch_mode = 0;
+       int dwim_new_local_branch = 1;
        struct option options[] = {
                OPT__QUIET(&opts.quiet),
                OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
@@ -597,6 +633,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
                OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+               { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
+                 "second guess 'git checkout no-such-branch'",
+                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };
        int has_dash_dash;
@@ -630,8 +669,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                opts.new_branch = argv0 + 1;
        }
 
-       if (opts.track == BRANCH_TRACK_UNSPECIFIED)
-               opts.track = git_branch_track;
        if (conflict_style) {
                opts.merge = 1; /* implied */
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
@@ -655,6 +692,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
         *   With no paths, if <something> is a commit, that is to
         *   switch to the branch or detach HEAD at it.
         *
+        *   With no paths, if <something> is _not_ a commit, no -t nor -b
+        *   was given, and there is a tracking branch whose name is
+        *   <something> in one and only one remote, then this is a short-hand
+        *   to fork local <something> from that remote tracking branch.
+        *
         *   Otherwise <something> shall not be ambiguous.
         *   - If it's *only* a reference, treat it like case (1).
         *   - If it's only a path, treat it like case (2).
@@ -677,7 +719,21 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                if (get_sha1(arg, rev)) {
                        if (has_dash_dash)          /* case (1) */
                                die("invalid reference: %s", arg);
-                       goto no_reference;          /* case (3 -> 2) */
+                       if (!patch_mode &&
+                           dwim_new_local_branch &&
+                           opts.track == BRANCH_TRACK_UNSPECIFIED &&
+                           !opts.new_branch &&
+                           !check_filename(NULL, arg) &&
+                           argc == 1) {
+                               const char *remote = unique_tracking_name(arg);
+                               if (!remote || get_sha1(remote, rev))
+                                       goto no_reference;
+                               opts.new_branch = arg;
+                               arg = remote;
+                               /* DWIMmed to create local branch */
+                       }
+                       else
+                               goto no_reference;
                }
 
                /* we can't end up being in (2) anymore, eat the argument */
@@ -715,6 +771,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        }
 
 no_reference:
+
+       if (opts.track == BRANCH_TRACK_UNSPECIFIED)
+               opts.track = git_branch_track;
+
        if (argc) {
                const char **pathspec = get_pathspec(prefix, argv);
 
index 5762a6f9d8191c79d4fd66d227038d59ab1e785e..caf3025031d83dc860b22c7798dd5f40b6b89ed2 100644 (file)
@@ -51,7 +51,9 @@ static struct option builtin_clone_options[] = {
        OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
                    "don't create a checkout"),
        OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
-       OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
+       { OPTION_BOOLEAN, 0, "naked", &option_bare, NULL,
+               "create a bare repository",
+               PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
        OPT_BOOLEAN(0, "mirror", &option_mirror,
                    "create a mirror repository (implies bare)"),
        OPT_BOOLEAN('l', "local", &option_local,
@@ -61,7 +63,7 @@ static struct option builtin_clone_options[] = {
        OPT_BOOLEAN('s', "shared", &option_shared,
                    "setup as shared repository"),
        OPT_BOOLEAN(0, "recursive", &option_recursive,
-                   "setup as shared repository"),
+                   "initialize submodules in the clone"),
        OPT_STRING(0, "template", &option_template, "path",
                   "path the template repository"),
        OPT_STRING(0, "reference", &option_reference, "repo",
@@ -377,8 +379,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, builtin_clone_options,
                             builtin_clone_usage, 0);
 
+       if (argc > 2)
+               usage_msg_opt("Too many arguments.",
+                       builtin_clone_usage, builtin_clone_options);
+
        if (argc == 0)
-               die("You must specify a repository to clone.");
+               usage_msg_opt("You must specify a repository to clone.",
+                       builtin_clone_usage, builtin_clone_options);
 
        if (option_mirror)
                option_bare = 1;
index cfa6b06e92924484376d853eef7171d163fe7fe1..d525b894ec1211476707acb06bdebe25d5828dbb 100644 (file)
@@ -725,8 +725,10 @@ static const char *find_author_by_nickname(const char *name)
        prepare_revision_walk(&revs);
        commit = get_revision(&revs);
        if (commit) {
+               struct pretty_print_context ctx = {0};
+               ctx.date_mode = DATE_NORMAL;
                strbuf_release(&buf);
-               format_commit_message(commit, "%an <%ae>", &buf, DATE_NORMAL);
+               format_commit_message(commit, "%an <%ae>", &buf, &ctx);
                return strbuf_detach(&buf, NULL);
        }
        die("No existing author found with '%s'", name);
@@ -983,8 +985,10 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
                initial_commit ? " (root-commit)" : "");
 
        if (!log_tree_commit(&rev, commit)) {
+               struct pretty_print_context ctx = {0};
                struct strbuf buf = STRBUF_INIT;
-               format_commit_message(commit, format + 7, &buf, DATE_NORMAL);
+               ctx.date_mode = DATE_NORMAL;
+               format_commit_message(commit, format + 7, &buf, &ctx);
                printf("%s\n", buf.buf);
                strbuf_release(&buf);
        }
index e1eba778a526f500b0a65a6b112e468f04a3f869..ca08519d9d6290f3cda4ee92e29e4acbf8325d0c 100644 (file)
@@ -372,6 +372,7 @@ static void show_info_page(const char *git_cmd)
        const char *page = cmd_to_page(git_cmd);
        setenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
        execlp("info", "info", "gitman", page, NULL);
+       die("no info viewer handled the request");
 }
 
 static void get_html_page_path(struct strbuf *page_path, const char *page)
@@ -416,9 +417,6 @@ int cmd_help(int argc, const char **argv, const char *prefix)
        const char *alias;
        load_command_list("git-", &main_cmds, &other_cmds);
 
-       setup_git_directory_gently(&nongit);
-       git_config(git_help_config, NULL);
-
        argc = parse_options(argc, argv, prefix, builtin_help_options,
                        builtin_help_usage, 0);
 
@@ -429,6 +427,9 @@ int cmd_help(int argc, const char **argv, const char *prefix)
                return 0;
        }
 
+       setup_git_directory_gently(&nongit);
+       git_config(git_help_config, NULL);
+
        if (!argv[0]) {
                printf("usage: %s\n\n", git_usage_string);
                list_common_cmds_help();
index 25e21ed41534c8c3067c2e0d5afe4284faa2881a..207a36178bafcbd755789fefb35b74054d1ff2fa 100644 (file)
@@ -1304,8 +1304,9 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
 
                if (verbose) {
                        struct strbuf buf = STRBUF_INIT;
+                       struct pretty_print_context ctx = {0};
                        pretty_print_commit(CMIT_FMT_ONELINE, commit,
-                                           &buf, 0, NULL, NULL, 0, 0);
+                                           &buf, &ctx);
                        printf("%c %s %s\n", sign,
                               sha1_to_hex(commit->object.sha1), buf.buf);
                        strbuf_release(&buf);
index 78a88f74769645f0be86aa77d3dee3f5e99c916f..b5bad0c184fc1ebc49759f211781ecd4031fd027 100644 (file)
@@ -86,10 +86,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                        pattern[j - i] = p;
                }
        }
-       remote = nongit ? NULL : remote_get(dest);
-       if (remote && !remote->url_nr)
+       remote = remote_get(dest);
+       if (!remote->url_nr)
                die("remote %s has no configured URL", dest);
-       transport = transport_get(remote, remote ? remote->url[0] : dest);
+       transport = transport_get(remote, remote->url[0]);
        if (uploadpack != NULL)
                transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
 
index b6b84286b26a4317dfd5185ae83fd861c6f9fa7d..c69a3051f38eb70f148015471d0c2df1df8db33b 100644 (file)
@@ -264,6 +264,7 @@ static void squash_message(void)
        struct strbuf out = STRBUF_INIT;
        struct commit_list *j;
        int fd;
+       struct pretty_print_context ctx = {0};
 
        printf("Squash commit -- not updating HEAD\n");
        fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
@@ -285,13 +286,15 @@ static void squash_message(void)
        if (prepare_revision_walk(&rev))
                die("revision walk setup failed");
 
+       ctx.abbrev = rev.abbrev;
+       ctx.date_mode = rev.date_mode;
+
        strbuf_addstr(&out, "Squashed commit of the following:\n");
        while ((commit = get_revision(&rev)) != NULL) {
                strbuf_addch(&out, '\n');
                strbuf_addf(&out, "commit %s\n",
                        sha1_to_hex(commit->object.sha1));
-               pretty_print_commit(rev.commit_format, commit, &out, rev.abbrev,
-                       NULL, NULL, rev.date_mode, 0);
+               pretty_print_commit(rev.commit_format, commit, &out, &ctx);
        }
        if (write(fd, out.buf, out.len) < 0)
                die_errno("Writing SQUASH_MSG");
index 02f9246cdb29903e9d7aafe47604f6882a3e7f86..4c91e944c21df3d5e02535115cdd6098ee49d86d 100644 (file)
@@ -1629,6 +1629,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
        struct thread_params *p;
        int i, ret, active_threads = 0;
 
+       if (!delta_search_threads)      /* --threads=0 means autodetect */
+               delta_search_threads = online_cpus();
        if (delta_search_threads <= 1) {
                find_deltas(list, &list_size, window, depth, processed);
                return;
@@ -2324,11 +2326,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (keep_unreachable && unpack_unreachable)
                die("--keep-unreachable and --unpack-unreachable are incompatible.");
 
-#ifdef THREADED_DELTA_SEARCH
-       if (!delta_search_threads)      /* --threads=0 means autodetect */
-               delta_search_threads = online_cpus();
-#endif
-
        prepare_packed_git();
 
        if (progress)
index b5cd2cdad04548f053d0a9ff24e661d4c3ee1d39..8631c06ed6cfdfe12286c5c72ee3f2b733be8986 100644 (file)
@@ -181,7 +181,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
                OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
-               OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror"),
+               OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
                OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
                OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
                OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
index 4ba1c12e0b6fedb056aebed6ffc8f8bb8d6cfd18..42cc8d8872afbc1302f14e089db430014330f7c3 100644 (file)
@@ -96,9 +96,10 @@ static void show_commit(struct commit *commit, void *data)
 
        if (revs->verbose_header && commit->buffer) {
                struct strbuf buf = STRBUF_INIT;
-               pretty_print_commit(revs->commit_format, commit,
-                                   &buf, revs->abbrev, NULL, NULL,
-                                   revs->date_mode, 0);
+               struct pretty_print_context ctx = {0};
+               ctx.abbrev = revs->abbrev;
+               ctx.date_mode = revs->date_mode;
+               pretty_print_commit(revs->commit_format, commit, &buf, &ctx);
                if (revs->graph) {
                        if (buf.len) {
                                if (revs->commit_format != CMIT_FMT_ONELINE)
index 4d4a3c82d6209ce3ec897dad0c69d58a329b4303..8aa63c7857fb3a704826bf223ddefb3e40f0eaf7 100644 (file)
@@ -158,9 +158,12 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
                    sha1_to_hex(commit->object.sha1));
        if (log->user_format) {
                struct strbuf buf = STRBUF_INIT;
-
-               pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf,
-                       DEFAULT_ABBREV, "", "", DATE_NORMAL, 0);
+               struct pretty_print_context ctx = {0};
+               ctx.abbrev = DEFAULT_ABBREV;
+               ctx.subject = "";
+               ctx.after_subject = "";
+               ctx.date_mode = DATE_NORMAL;
+               pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf, &ctx);
                insert_one_record(log, author, buf.buf);
                strbuf_release(&buf);
                return;
index be95930b783f47ade274e281227844e795729f5a..9f13caa76d3b147993b2cf39397d2f5761cfca22 100644 (file)
@@ -293,8 +293,8 @@ static void show_one_commit(struct commit *commit, int no_name)
        struct commit_name *name = commit->util;
 
        if (commit->object.parsed) {
-               pretty_print_commit(CMIT_FMT_ONELINE, commit,
-                                   &pretty, 0, NULL, NULL, 0, 0);
+               struct pretty_print_context ctx = {0};
+               pretty_print_commit(CMIT_FMT_ONELINE, commit, &pretty, &ctx);
                pretty_str = pretty.buf;
        }
        if (!prefixcmp(pretty_str, "[PATCH] "))
diff --git a/cache.h b/cache.h
index 96840c7af78aac3c760586dd8018652ec9ddefed..71a731dbc988a8a22d0a2e1f8f3a5223f4c5d67a 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -396,6 +396,7 @@ extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
 extern const char *prefix_filename(const char *prefix, int len, const char *path);
+extern int check_filename(const char *prefix, const char *name);
 extern void verify_filename(const char *prefix, const char *name);
 extern void verify_non_filename(const char *prefix, const char *name);
 
index fedbd5e5267ec4beaf1f245a879918a2685c10b9..6393e1b36218e5f8970b0c43092b07f5d94b0bce 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -132,8 +132,8 @@ struct commit_graft *read_graft_line(char *buf, int len)
        int i;
        struct commit_graft *graft = NULL;
 
-       if (buf[len-1] == '\n')
-               buf[--len] = 0;
+       while (len && isspace(buf[len-1]))
+               buf[--len] = '\0';
        if (buf[0] == '#' || buf[0] == '\0')
                return NULL;
        if ((len + 1) % 41) {
index 95f981a1a93989d89edb0c5b850fa86db2071b50..422f778f3f5b997ea1a3d8569cf6fa573481fff1 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -63,6 +63,16 @@ enum cmit_fmt {
        CMIT_FMT_UNSPECIFIED,
 };
 
+struct pretty_print_context
+{
+       int abbrev;
+       const char *subject;
+       const char *after_subject;
+       enum date_mode date_mode;
+       int need_8bit_cte;
+       struct reflog_walk_info *reflog_info;
+};
+
 extern int non_ascii(int);
 extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
@@ -71,12 +81,10 @@ extern char *reencode_commit_message(const struct commit *commit,
 extern void get_commit_format(const char *arg, struct rev_info *);
 extern void format_commit_message(const struct commit *commit,
                                  const char *format, struct strbuf *sb,
-                                 enum date_mode dmode);
-extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
-                                struct strbuf *,
-                                int abbrev, const char *subject,
-                                const char *after_subject, enum date_mode,
-                               int need_8bit_cte);
+                                 const struct pretty_print_context *context);
+extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
+                               struct strbuf *sb,
+                               const struct pretty_print_context *context);
 void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
                   const char *line, enum date_mode dmode,
                   const char *encoding);
index 5cc4acbfccef771769974b9f7cd8f6bca9321354..279e0b48b15e091fc0ca975c3efbd461ab02c149 100644 (file)
@@ -28,6 +28,16 @@ static inline uint32_t default_swab32(uint32_t val)
        } \
        __res; })
 
+#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+
+#include <stdlib.h>
+
+#define bswap32(x) _byteswap_ulong(x)
+
+#endif
+
+#ifdef bswap32
+
 #undef ntohl
 #undef htonl
 #define ntohl(x) bswap32(x)
index be94ba18d2b42a5b67f6853cac4611fd06c9c71e..cfa74adcc23881f229c84c29a78d7bfd4aa2f2a4 100644 (file)
@@ -178,6 +178,7 @@ sub createLibProject {
                                MinimalRebuild="true"
                                RuntimeLibrary="1"
                                UsePrecompiledHeader="0"
+                               ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb"
                                WarningLevel="3"
                                DebugInformationFormat="3"
                        />
@@ -244,6 +245,7 @@ sub createLibProject {
                                RuntimeLibrary="0"
                                EnableFunctionLevelLinking="true"
                                UsePrecompiledHeader="0"
+                               ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb"
                                WarningLevel="3"
                                DebugInformationFormat="3"
                        />
@@ -401,6 +403,7 @@ sub createAppProject {
                                MinimalRebuild="true"
                                RuntimeLibrary="1"
                                UsePrecompiledHeader="0"
+                               ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb"
                                WarningLevel="3"
                                DebugInformationFormat="3"
                        />
@@ -472,6 +475,7 @@ sub createAppProject {
                                RuntimeLibrary="0"
                                EnableFunctionLevelLinking="true"
                                UsePrecompiledHeader="0"
+                               ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb"
                                WarningLevel="3"
                                DebugInformationFormat="3"
                        />
diff --git a/diff.c b/diff.c
index b0c7e616a6dc41cc9052cba381ea534a72759211..3ad1f8c31046ee3dae8a8e9bed6dc9f5a5929b78 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -13,6 +13,7 @@
 #include "utf8.h"
 #include "userdiff.h"
 #include "sigchain.h"
+#include "submodule.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -1557,6 +1558,17 @@ static void builtin_diff(const char *name_a,
        const char *a_prefix, *b_prefix;
        const char *textconv_one = NULL, *textconv_two = NULL;
 
+       if (DIFF_OPT_TST(o, SUBMODULE_LOG) &&
+                       (!one->mode || S_ISGITLINK(one->mode)) &&
+                       (!two->mode || S_ISGITLINK(two->mode))) {
+               const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
+               const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
+               show_submodule_summary(o->file, one ? one->path : two->path,
+                               one->sha1, two->sha1,
+                               del, add, reset);
+               return;
+       }
+
        if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
                textconv_one = get_textconv(one);
                textconv_two = get_textconv(two);
@@ -2757,6 +2769,12 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
        else if (!strcmp(arg, "--ignore-submodules"))
                DIFF_OPT_SET(options, IGNORE_SUBMODULES);
+       else if (!strcmp(arg, "--submodule"))
+               DIFF_OPT_SET(options, SUBMODULE_LOG);
+       else if (!prefixcmp(arg, "--submodule=")) {
+               if (!strcmp(arg + 12, "log"))
+                       DIFF_OPT_SET(options, SUBMODULE_LOG);
+       }
 
        /* misc options */
        else if (!strcmp(arg, "-z"))
diff --git a/diff.h b/diff.h
index 6616877ee5d15a8101cbdea0271cc18f8837d2f1..2740421cfe9985a57f61855dc6372e8402231e0e 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -66,6 +66,9 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
 #define DIFF_OPT_DIRSTAT_CUMULATIVE  (1 << 19)
 #define DIFF_OPT_DIRSTAT_BY_FILE     (1 << 20)
 #define DIFF_OPT_ALLOW_TEXTCONV      (1 << 21)
+
+#define DIFF_OPT_SUBMODULE_LOG       (1 << 23)
+
 #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
 #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
 #define DIFF_OPT_CLR(opts, flag)    ((opts)->flags &= ~DIFF_OPT_##flag)
index 6f6f03966f5905c799a1a67df58e11b0a5f7564c..8b3c5858a901619eecd162229f92eb431b3e63f9 100755 (executable)
@@ -13,8 +13,8 @@ git bisect skip [(<rev>|<range>)...]
         mark <rev>... untestable revisions.
 git bisect next
         find next bisection to test and check it out.
-git bisect reset [<branch>]
-        finish bisection search and go back to branch.
+git bisect reset [<commit>]
+        finish bisection search and go back to commit.
 git bisect visualize
         show bisect status in gitk.
 git bisect replay <logfile>
@@ -311,8 +311,8 @@ bisect_reset() {
        }
        case "$#" in
        0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
-       1) git show-ref --verify --quiet -- "refs/heads/$1" ||
-              die "$1 does not seem to be a valid branch"
+       1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null ||
+              die "'$1' is not a valid commit"
           branch="$1" ;;
        *)
            usage ;;
index a1879e3ace72704086010dc5528d3897a91a6d02..53ad248ee505091d8e11cb9eb82ebb9b017b4262 100755 (executable)
@@ -416,7 +416,12 @@ do_next () {
                ;;
        *)
                warn "Unknown command: $command $sha1 $rest"
-               die_with_patch $sha1 "Please fix this in the file $TODO."
+               if git rev-parse --verify -q "$sha1" >/dev/null
+               then
+                       die_with_patch $sha1 "Please fix this in the file $TODO."
+               else
+                       die "Please fix this in the file $TODO."
+               fi
                ;;
        esac
        test -s "$TODO" && return
index 4febbbfa5d13b241e9bfcc479c6767a90bd12919..f796c2fe24f0eaec3de45bc5bf14f7dd2e29f4bd 100755 (executable)
@@ -205,8 +205,7 @@ have_stash () {
 
 list_stash () {
        have_stash || return 0
-       git log --no-color --pretty=oneline -g "$@" $ref_stash -- |
-       sed -n -e 's/^[.0-9a-f]* refs\///p'
+       git log --format="%gd: %gs" -g "$@" $ref_stash --
 }
 
 show_stash () {
@@ -383,11 +382,6 @@ test -n "$seen_non_option" || set "save" "$@"
 case "$1" in
 list)
        shift
-       if test $# = 0
-       then
-               set x -n 10
-               shift
-       fi
        list_stash "$@"
        ;;
 show)
index f7d54f2f1b132d54adda6a9ca5f8e1332856709f..0fdf159f8098532e3ed77251d36e163b695310ba 100644 (file)
@@ -179,8 +179,10 @@ void get_patch_filename(struct commit *commit, int nr, const char *suffix,
        strbuf_addf(buf, commit ? "%04d-" : "%d", nr);
        if (commit) {
                int max_len = start_len + FORMAT_PATCH_NAME_MAX - suffix_len;
+               struct pretty_print_context ctx = {0};
+               ctx.date_mode = DATE_NORMAL;
 
-               format_commit_message(commit, "%f", buf, DATE_NORMAL);
+               format_commit_message(commit, "%f", buf, &ctx);
                if (max_len < buf->len)
                        strbuf_setlen(buf, max_len);
                strbuf_addstr(buf, suffix);
@@ -277,10 +279,9 @@ void show_log(struct rev_info *opt)
        struct strbuf msgbuf = STRBUF_INIT;
        struct log_info *log = opt->loginfo;
        struct commit *commit = log->commit, *parent = log->parent;
-       int abbrev = opt->diffopt.abbrev;
        int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
-       const char *subject = NULL, *extra_headers = opt->extra_headers;
-       int need_8bit_cte = 0;
+       const char *extra_headers = opt->extra_headers;
+       struct pretty_print_context ctx = {0};
 
        opt->loginfo = NULL;
        if (!opt->verbose_header) {
@@ -347,8 +348,8 @@ void show_log(struct rev_info *opt)
         */
 
        if (opt->commit_format == CMIT_FMT_EMAIL) {
-               log_write_email_headers(opt, commit, &subject, &extra_headers,
-                                       &need_8bit_cte);
+               log_write_email_headers(opt, commit, &ctx.subject, &extra_headers,
+                                       &ctx.need_8bit_cte);
        } else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
                fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout);
                if (opt->commit_format != CMIT_FMT_ONELINE)
@@ -405,11 +406,13 @@ void show_log(struct rev_info *opt)
        /*
         * And then the pretty-printed message itself
         */
-       if (need_8bit_cte >= 0)
-               need_8bit_cte = has_non_ascii(opt->add_signoff);
-       pretty_print_commit(opt->commit_format, commit, &msgbuf,
-                           abbrev, subject, extra_headers, opt->date_mode,
-                           need_8bit_cte);
+       if (ctx.need_8bit_cte >= 0)
+               ctx.need_8bit_cte = has_non_ascii(opt->add_signoff);
+       ctx.date_mode = opt->date_mode;
+       ctx.abbrev = opt->diffopt.abbrev;
+       ctx.after_subject = extra_headers;
+       ctx.reflog_info = opt->reflog_info;
+       pretty_print_commit(opt->commit_format, commit, &msgbuf, &ctx);
 
        if (opt->add_signoff)
                append_signoff(&msgbuf, opt->add_signoff);
index 587101f846b945d7de219f468699e75565a7e9c0..da15cf2a80d08e38b4b0bb279e378b72dbe49cc7 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -7,6 +7,7 @@
 #include "mailmap.h"
 #include "log-tree.h"
 #include "color.h"
+#include "reflog-walk.h"
 
 static char *user_format;
 
@@ -442,7 +443,7 @@ struct chunk {
 
 struct format_commit_context {
        const struct commit *commit;
-       enum date_mode dmode;
+       const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
 
@@ -701,6 +702,22 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'd':
                format_decoration(sb, commit);
                return 1;
+       case 'g':               /* reflog info */
+               switch(placeholder[1]) {
+               case 'd':       /* reflog selector */
+               case 'D':
+                       if (c->pretty_ctx->reflog_info)
+                               get_reflog_selector(sb,
+                                                   c->pretty_ctx->reflog_info,
+                                                   c->pretty_ctx->date_mode,
+                                                   (placeholder[1] == 'd'));
+                       return 2;
+               case 's':       /* reflog message */
+                       if (c->pretty_ctx->reflog_info)
+                               get_reflog_message(sb, c->pretty_ctx->reflog_info);
+                       return 2;
+               }
+               return 0;       /* unknown %g placeholder */
        }
 
        /* For the rest we have to parse the commit header. */
@@ -711,11 +728,11 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->author.off, c->author.len,
-                                  c->dmode);
+                                  c->pretty_ctx->date_mode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->committer.off, c->committer.len,
-                                  c->dmode);
+                                  c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
                strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
                return 1;
@@ -741,13 +758,13 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
 
 void format_commit_message(const struct commit *commit,
                           const char *format, struct strbuf *sb,
-                          enum date_mode dmode)
+                          const struct pretty_print_context *pretty_ctx)
 {
        struct format_commit_context context;
 
        memset(&context, 0, sizeof(context));
        context.commit = commit;
-       context.dmode = dmode;
+       context.pretty_ctx = pretty_ctx;
        strbuf_expand(sb, format, format_commit_item, &context);
 }
 
@@ -900,18 +917,18 @@ char *reencode_commit_message(const struct commit *commit, const char **encoding
 }
 
 void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
-                        struct strbuf *sb, int abbrev,
-                        const char *subject, const char *after_subject,
-                        enum date_mode dmode, int need_8bit_cte)
+                        struct strbuf *sb,
+                        const struct pretty_print_context *context)
 {
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg = commit->buffer;
        char *reencoded;
        const char *encoding;
+       int need_8bit_cte = context->need_8bit_cte;
 
        if (fmt == CMIT_FMT_USERFORMAT) {
-               format_commit_message(commit, user_format, sb, dmode);
+               format_commit_message(commit, user_format, sb, context);
                return;
        }
 
@@ -946,8 +963,9 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
                }
        }
 
-       pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
-       if (fmt != CMIT_FMT_ONELINE && !subject) {
+       pp_header(fmt, context->abbrev, context->date_mode, encoding,
+                 commit, &msg, sb);
+       if (fmt != CMIT_FMT_ONELINE && !context->subject) {
                strbuf_addch(sb, '\n');
        }
 
@@ -956,8 +974,8 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 
        /* These formats treat the title line specially. */
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
-               pp_title_line(fmt, &msg, sb, subject,
-                             after_subject, encoding, need_8bit_cte);
+               pp_title_line(fmt, &msg, sb, context->subject,
+                             context->after_subject, encoding, need_8bit_cte);
 
        beginning_of_body = sb->len;
        if (fmt != CMIT_FMT_ONELINE)
index 5623ea6b48a2f355e8866eabb2805b51b4127a4a..caba4f743f2dcc1cf7046cec294f242b2af19052 100644 (file)
@@ -8,6 +8,7 @@
 
 struct complete_reflogs {
        char *ref;
+       const char *short_ref;
        struct reflog_info {
                unsigned char osha1[20], nsha1[20];
                char *email;
@@ -241,36 +242,74 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
        commit->object.flags &= ~(ADDED | SEEN | SHOWN);
 }
 
-void show_reflog_message(struct reflog_walk_info *info, int oneline,
+void get_reflog_selector(struct strbuf *sb,
+                        struct reflog_walk_info *reflog_info,
+                        enum date_mode dmode,
+                        int shorten)
+{
+       struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
+       struct reflog_info *info;
+       const char *printed_ref;
+
+       if (!commit_reflog)
+               return;
+
+       if (shorten) {
+               if (!commit_reflog->reflogs->short_ref)
+                       commit_reflog->reflogs->short_ref
+                               = shorten_unambiguous_ref(commit_reflog->reflogs->ref, 0);
+               printed_ref = commit_reflog->reflogs->short_ref;
+       } else {
+               printed_ref = commit_reflog->reflogs->ref;
+       }
+
+       strbuf_addf(sb, "%s@{", printed_ref);
+       if (commit_reflog->flag || dmode) {
+               info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
+               strbuf_addstr(sb, show_date(info->timestamp, info->tz, dmode));
+       } else {
+               strbuf_addf(sb, "%d", commit_reflog->reflogs->nr
+                           - 2 - commit_reflog->recno);
+       }
+
+       strbuf_addch(sb, '}');
+}
+
+void get_reflog_message(struct strbuf *sb,
+                       struct reflog_walk_info *reflog_info)
+{
+       struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
+       struct reflog_info *info;
+       size_t len;
+
+       if (!commit_reflog)
+               return;
+
+       info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
+       len = strlen(info->message);
+       if (len > 0)
+               len--; /* strip away trailing newline */
+       strbuf_add(sb, info->message, len);
+}
+
+void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
        enum date_mode dmode)
 {
-       if (info && info->last_commit_reflog) {
-               struct commit_reflog *commit_reflog = info->last_commit_reflog;
+       if (reflog_info && reflog_info->last_commit_reflog) {
+               struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
                struct reflog_info *info;
+               struct strbuf selector = STRBUF_INIT;
 
                info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
+               get_reflog_selector(&selector, reflog_info, dmode, 0);
                if (oneline) {
-                       printf("%s@{", commit_reflog->reflogs->ref);
-                       if (commit_reflog->flag || dmode)
-                               printf("%s", show_date(info->timestamp,
-                                                      info->tz,
-                                                      dmode));
-                       else
-                               printf("%d", commit_reflog->reflogs->nr
-                                      - 2 - commit_reflog->recno);
-                       printf("}: %s", info->message);
+                       printf("%s: %s", selector.buf, info->message);
                }
                else {
-                       printf("Reflog: %s@{", commit_reflog->reflogs->ref);
-                       if (commit_reflog->flag || dmode)
-                               printf("%s", show_date(info->timestamp,
-                                                       info->tz,
-                                                       dmode));
-                       else
-                               printf("%d", commit_reflog->reflogs->nr
-                                      - 2 - commit_reflog->recno);
-                       printf("} (%s)\nReflog message: %s",
-                              info->email, info->message);
+                       printf("Reflog: %s (%s)\nReflog message: %s",
+                              selector.buf, info->email, info->message);
                }
+
+               strbuf_release(&selector);
        }
 }
index 74c90964bd95dcd97a5acde83c83b2f3b61c2441..7bd2cd4c4e5cd9d51e645509eeacc49a83a44ba7 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "cache.h"
 
+struct reflog_walk_info;
+
 extern void init_reflog_walk(struct reflog_walk_info** info);
 extern int add_reflog_for_walk(struct reflog_walk_info *info,
                struct commit *commit, const char *name);
@@ -10,5 +12,11 @@ extern void fake_reflog_parent(struct reflog_walk_info *info,
                struct commit *commit);
 extern void show_reflog_message(struct reflog_walk_info *info, int,
                enum date_mode);
+extern void get_reflog_message(struct strbuf *sb,
+               struct reflog_walk_info *reflog_info);
+extern void get_reflog_selector(struct strbuf *sb,
+               struct reflog_walk_info *reflog_info,
+               enum date_mode dmode,
+               int shorten);
 
 #endif
index 2faf1c634415d139f15c4829937e0460be31dc1d..ebdab3603ec767b42ce04e0de2c3deeb516f2525 100644 (file)
@@ -82,9 +82,10 @@ int main(int argc, const char **argv)
        struct strbuf buf = STRBUF_INIT;
        const char *url;
        struct walker *walker = NULL;
+       int nongit;
 
        git_extract_argv0_path(argv[0]);
-       setup_git_directory();
+       setup_git_directory_gently(&nongit);
        if (argc < 2) {
                fprintf(stderr, "Remote needed\n");
                return 1;
@@ -103,6 +104,8 @@ int main(int argc, const char **argv)
                        break;
                if (!prefixcmp(buf.buf, "fetch ")) {
                        char *obj = buf.buf + strlen("fetch ");
+                       if (nongit)
+                               die("Fetch attempted without a local repo");
                        if (!walker)
                                walker = get_http_walker(url, remote);
                        walker->get_all = 1;
diff --git a/setup.c b/setup.c
index 029371e5844a1069d62456c6bb51028efbb671c4..f67250b7c1f7b5a62c30de0122c404554357f61b 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -61,6 +61,19 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
        return path;
 }
 
+int check_filename(const char *prefix, const char *arg)
+{
+       const char *name;
+       struct stat st;
+
+       name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
+       if (!lstat(name, &st))
+               return 1; /* file exists */
+       if (errno == ENOENT || errno == ENOTDIR)
+               return 0; /* file does not exist */
+       die_errno("failed to stat '%s'", arg);
+}
+
 /*
  * Verify a filename that we got as an argument for a pathspec
  * entry. Note that a filename that begins with "-" never verifies
@@ -70,18 +83,12 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
  */
 void verify_filename(const char *prefix, const char *arg)
 {
-       const char *name;
-       struct stat st;
-
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
-       name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
-       if (!lstat(name, &st))
+       if (check_filename(prefix, arg))
                return;
-       if (errno == ENOENT)
-               die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
-                   "Use '--' to separate paths from revisions", arg);
-       die_errno("failed to stat '%s'", arg);
+       die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
+           "Use '--' to separate paths from revisions", arg);
 }
 
 /*
@@ -91,19 +98,14 @@ void verify_filename(const char *prefix, const char *arg)
  */
 void verify_non_filename(const char *prefix, const char *arg)
 {
-       const char *name;
-       struct stat st;
-
        if (!is_inside_work_tree() || is_inside_git_dir())
                return;
        if (*arg == '-')
                return; /* flag */
-       name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
-       if (!lstat(name, &st))
-               die("ambiguous argument '%s': both revision and filename\n"
-                   "Use '--' to separate filenames from revisions", arg);
-       if (errno != ENOENT && errno != ENOTDIR)
-               die_errno("failed to stat '%s'", arg);
+       if (!check_filename(prefix, arg))
+               return;
+       die("ambiguous argument '%s': both revision and filename\n"
+           "Use '--' to separate filenames from revisions", arg);
 }
 
 const char **get_pathspec(const char *prefix, const char **pathspec)
diff --git a/submodule.c b/submodule.c
new file mode 100644 (file)
index 0000000..461faf0
--- /dev/null
@@ -0,0 +1,114 @@
+#include "cache.h"
+#include "submodule.h"
+#include "dir.h"
+#include "diff.h"
+#include "commit.h"
+#include "revision.h"
+
+int add_submodule_odb(const char *path)
+{
+       struct strbuf objects_directory = STRBUF_INIT;
+       struct alternate_object_database *alt_odb;
+
+       strbuf_addf(&objects_directory, "%s/.git/objects/", path);
+       if (!is_directory(objects_directory.buf))
+               return -1;
+
+       /* avoid adding it twice */
+       for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
+               if (alt_odb->name - alt_odb->base == objects_directory.len &&
+                               !strncmp(alt_odb->base, objects_directory.buf,
+                                       objects_directory.len))
+                       return 0;
+
+       alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
+       alt_odb->next = alt_odb_list;
+       strcpy(alt_odb->base, objects_directory.buf);
+       alt_odb->name = alt_odb->base + objects_directory.len;
+       alt_odb->name[2] = '/';
+       alt_odb->name[40] = '\0';
+       alt_odb->name[41] = '\0';
+       alt_odb_list = alt_odb;
+       prepare_alt_odb();
+       return 0;
+}
+
+void show_submodule_summary(FILE *f, const char *path,
+               unsigned char one[20], unsigned char two[20],
+               const char *del, const char *add, const char *reset)
+{
+       struct rev_info rev;
+       struct commit *commit, *left = left, *right;
+       struct commit_list *merge_bases, *list;
+       const char *message = NULL;
+       struct strbuf sb = STRBUF_INIT;
+       static const char *format = "  %m %s";
+       int fast_forward = 0, fast_backward = 0;
+
+       if (is_null_sha1(two))
+               message = "(submodule deleted)";
+       else if (add_submodule_odb(path))
+               message = "(not checked out)";
+       else if (is_null_sha1(one))
+               message = "(new submodule)";
+       else if (!(left = lookup_commit_reference(one)) ||
+                !(right = lookup_commit_reference(two)))
+               message = "(commits not present)";
+
+       if (!message) {
+               init_revisions(&rev, NULL);
+               setup_revisions(0, NULL, &rev, NULL);
+               rev.left_right = 1;
+               rev.first_parent_only = 1;
+               left->object.flags |= SYMMETRIC_LEFT;
+               add_pending_object(&rev, &left->object, path);
+               add_pending_object(&rev, &right->object, path);
+               merge_bases = get_merge_bases(left, right, 1);
+               if (merge_bases) {
+                       if (merge_bases->item == left)
+                               fast_forward = 1;
+                       else if (merge_bases->item == right)
+                               fast_backward = 1;
+               }
+               for (list = merge_bases; list; list = list->next) {
+                       list->item->object.flags |= UNINTERESTING;
+                       add_pending_object(&rev, &list->item->object,
+                               sha1_to_hex(list->item->object.sha1));
+               }
+               if (prepare_revision_walk(&rev))
+                       message = "(revision walker failed)";
+       }
+
+       strbuf_addf(&sb, "Submodule %s %s..", path,
+                       find_unique_abbrev(one, DEFAULT_ABBREV));
+       if (!fast_backward && !fast_forward)
+               strbuf_addch(&sb, '.');
+       strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
+       if (message)
+               strbuf_addf(&sb, " %s\n", message);
+       else
+               strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
+       fwrite(sb.buf, sb.len, 1, f);
+
+       if (!message) {
+               while ((commit = get_revision(&rev))) {
+                       struct pretty_print_context ctx = {0};
+                       ctx.date_mode = rev.date_mode;
+                       strbuf_setlen(&sb, 0);
+                       if (commit->object.flags & SYMMETRIC_LEFT) {
+                               if (del)
+                                       strbuf_addstr(&sb, del);
+                       }
+                       else if (add)
+                               strbuf_addstr(&sb, add);
+                       format_commit_message(commit, format, &sb, &ctx);
+                       if (reset)
+                               strbuf_addstr(&sb, reset);
+                       strbuf_addch(&sb, '\n');
+                       fprintf(f, "%s", sb.buf);
+               }
+               clear_commit_marks(left, ~0);
+               clear_commit_marks(right, ~0);
+       }
+       strbuf_release(&sb);
+}
diff --git a/submodule.h b/submodule.h
new file mode 100644 (file)
index 0000000..4c0269d
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef SUBMODULE_H
+#define SUBMODULE_H
+
+void show_submodule_summary(FILE *f, const char *path,
+               unsigned char one[20], unsigned char two[20],
+               const char *del, const char *add, const char *reset);
+
+#endif
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
new file mode 100755 (executable)
index 0000000..eb45afb
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+test_description='Test git check-ref-format'
+
+. ./test-lib.sh
+
+valid_ref() {
+       test_expect_success "ref name '$1' is valid" \
+               "git check-ref-format '$1'"
+}
+invalid_ref() {
+       test_expect_success "ref name '$1' is not valid" \
+               "test_must_fail git check-ref-format '$1'"
+}
+
+valid_ref 'heads/foo'
+invalid_ref 'foo'
+valid_ref 'foo/bar/baz'
+valid_ref 'refs///heads/foo'
+invalid_ref 'heads/foo/'
+invalid_ref './foo'
+invalid_ref '.refs/foo'
+invalid_ref 'heads/foo..bar'
+invalid_ref 'heads/foo?bar'
+valid_ref 'foo./bar'
+invalid_ref 'heads/foo.lock'
+valid_ref 'heads/foo@bar'
+invalid_ref 'heads/v@{ation'
+invalid_ref 'heads/foo\bar'
+
+test_expect_success "check-ref-format --branch @{-1}" '
+       T=$(git write-tree) &&
+       sha1=$(echo A | git commit-tree $T) &&
+       git update-ref refs/heads/master $sha1 &&
+       git update-ref refs/remotes/origin/master $sha1
+       git checkout master &&
+       git checkout origin/master &&
+       git checkout master &&
+       refname=$(git check-ref-format --branch @{-1}) &&
+       test "$refname" = "$sha1" &&
+       refname2=$(git check-ref-format --branch @{-2}) &&
+       test "$refname2" = master'
+
+valid_ref_normalized() {
+       test_expect_success "ref name '$1' simplifies to '$2'" "
+               refname=\$(git check-ref-format --print '$1') &&
+               test \"\$refname\" = '$2'"
+}
+invalid_ref_normalized() {
+       test_expect_success "check-ref-format --print rejects '$1'" "
+               test_must_fail git check-ref-format --print '$1'"
+}
+
+valid_ref_normalized 'heads/foo' 'heads/foo'
+valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo'
+invalid_ref_normalized 'foo'
+invalid_ref_normalized 'heads/foo/../bar'
+invalid_ref_normalized 'heads/./foo'
+invalid_ref_normalized 'heads\foo'
+
+test_done
diff --git a/t/t4041-diff-submodule.sh b/t/t4041-diff-submodule.sh
new file mode 100755 (executable)
index 0000000..5bb4fed
--- /dev/null
@@ -0,0 +1,260 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin
+#
+
+test_description='Support for verbose submodule differences in git diff
+
+This test tries to verify the sanity of the --submodule option of git diff.
+'
+
+. ./test-lib.sh
+
+add_file () {
+       sm=$1
+       shift
+       owd=$(pwd)
+       cd "$sm"
+       for name; do
+               echo "$name" > "$name" &&
+               git add "$name" &&
+               test_tick &&
+               git commit -m "Add $name"
+       done >/dev/null
+       git rev-parse --verify HEAD | cut -c1-7
+       cd "$owd"
+}
+commit_file () {
+       test_tick &&
+       git commit "$@" -m "Commit $*" >/dev/null
+}
+
+test_create_repo sm1 &&
+add_file . foo >/dev/null
+
+head1=$(add_file sm1 foo1 foo2)
+
+test_expect_success 'added submodule' "
+       git add sm1 &&
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 0000000...$head1 (new submodule)
+EOF
+"
+
+commit_file sm1 &&
+head2=$(add_file sm1 foo3)
+
+test_expect_success 'modified submodule(forward)' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head1..$head2:
+  > Add foo3
+EOF
+"
+
+test_expect_success 'modified submodule(forward)' "
+       git diff --submodule=log >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head1..$head2:
+  > Add foo3
+EOF
+"
+
+test_expect_success 'modified submodule(forward) --submodule' "
+       git diff --submodule >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head1..$head2:
+  > Add foo3
+EOF
+"
+
+fullhead1=$(cd sm1; git rev-list --max-count=1 $head1)
+fullhead2=$(cd sm1; git rev-list --max-count=1 $head2)
+test_expect_success 'modified submodule(forward) --submodule=short' "
+       git diff --submodule=short >actual &&
+       diff actual - <<-EOF
+diff --git a/sm1 b/sm1
+index $head1..$head2 160000
+--- a/sm1
++++ b/sm1
+@@ -1 +1 @@
+-Subproject commit $fullhead1
++Subproject commit $fullhead2
+EOF
+"
+
+commit_file sm1 &&
+cd sm1 &&
+git reset --hard HEAD~2 >/dev/null &&
+head3=$(git rev-parse --verify HEAD | cut -c1-7) &&
+cd ..
+
+test_expect_success 'modified submodule(backward)' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head2..$head3 (rewind):
+  < Add foo3
+  < Add foo2
+EOF
+"
+
+head4=$(add_file sm1 foo4 foo5) &&
+head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
+test_expect_success 'modified submodule(backward and forward)' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head2...$head4:
+  > Add foo5
+  > Add foo4
+  < Add foo3
+  < Add foo2
+EOF
+"
+
+commit_file sm1 &&
+mv sm1 sm1-bak &&
+echo sm1 >sm1 &&
+head5=$(git hash-object sm1 | cut -c1-7) &&
+git add sm1 &&
+rm -f sm1 &&
+mv sm1-bak sm1
+
+test_expect_success 'typechanged submodule(submodule->blob), --cached' "
+       git diff --submodule=log --cached >actual &&
+       diff actual - <<-EOF
+Submodule sm1 41fbea9...0000000 (submodule deleted)
+diff --git a/sm1 b/sm1
+new file mode 100644
+index 0000000..9da5fb8
+--- /dev/null
++++ b/sm1
+@@ -0,0 +1 @@
++sm1
+EOF
+"
+
+test_expect_success 'typechanged submodule(submodule->blob)' "
+       git diff --submodule=log >actual &&
+       diff actual - <<-EOF
+diff --git a/sm1 b/sm1
+deleted file mode 100644
+index 9da5fb8..0000000
+--- a/sm1
++++ /dev/null
+@@ -1 +0,0 @@
+-sm1
+Submodule sm1 0000000...$head4 (new submodule)
+EOF
+"
+
+rm -rf sm1 &&
+git checkout-index sm1
+test_expect_success 'typechanged submodule(submodule->blob)' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head4...0000000 (submodule deleted)
+diff --git a/sm1 b/sm1
+new file mode 100644
+index 0000000..$head5
+--- /dev/null
++++ b/sm1
+@@ -0,0 +1 @@
++sm1
+EOF
+"
+
+rm -f sm1 &&
+test_create_repo sm1 &&
+head6=$(add_file sm1 foo6 foo7)
+fullhead6=$(cd sm1; git rev-list --max-count=1 $head6)
+test_expect_success 'nonexistent commit' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head4...$head6 (commits not present)
+EOF
+"
+
+commit_file
+test_expect_success 'typechanged submodule(blob->submodule)' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+diff --git a/sm1 b/sm1
+deleted file mode 100644
+index $head5..0000000
+--- a/sm1
++++ /dev/null
+@@ -1 +0,0 @@
+-sm1
+Submodule sm1 0000000...$head6 (new submodule)
+EOF
+"
+
+commit_file sm1 &&
+rm -rf sm1
+test_expect_success 'deleted submodule' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+EOF
+"
+
+test_create_repo sm2 &&
+head7=$(add_file sm2 foo8 foo9) &&
+git add sm2
+
+test_expect_success 'multiple submodules' "
+       git diff-index -p --submodule=log HEAD >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+"
+
+test_expect_success 'path filter' "
+       git diff-index -p --submodule=log HEAD sm2 >actual &&
+       diff actual - <<-EOF
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+"
+
+commit_file sm2
+test_expect_success 'given commit' "
+       git diff-index -p --submodule=log HEAD^ >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+"
+
+test_expect_success 'given commit --submodule' "
+       git diff-index -p --submodule HEAD^ >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+"
+
+fullhead7=$(cd sm2; git rev-list --max-count=1 $head7)
+
+test_expect_success 'given commit --submodule=short' "
+       git diff-index -p --submodule=short HEAD^ >actual &&
+       diff actual - <<-EOF
+diff --git a/sm1 b/sm1
+deleted file mode 160000
+index $head6..0000000
+--- a/sm1
++++ /dev/null
+@@ -1 +0,0 @@
+-Subproject commit $fullhead6
+diff --git a/sm2 b/sm2
+new file mode 160000
+index 0000000..$head7
+--- /dev/null
++++ b/sm2
+@@ -0,0 +1 @@
++Subproject commit $fullhead7
+EOF
+"
+
+test_done
index 59d1f6283bec5cf7740d988dfd090c1463389c71..7f61ab0e522fd28c5e10594f03ed9076f9f5ce42 100755 (executable)
@@ -162,4 +162,22 @@ test_expect_success 'empty email' '
        }
 '
 
+test_expect_success '"%h %gD: %gs" is same as git-reflog' '
+       git reflog >expect &&
+       git log -g --format="%h %gD: %gs" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '"%h %gD: %gs" is same as git-reflog (with date)' '
+       git reflog --date=raw >expect &&
+       git log -g --format="%h %gD: %gs" --date=raw >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '%gd shortens ref name' '
+       echo "master@{0}" >expect.gd-short &&
+       git log -g -1 --format=%gd refs/heads/master >actual.gd-short &&
+       test_cmp expect.gd-short actual.gd-short
+'
+
 test_done
old mode 100644 (file)
new mode 100755 (executable)
index 8000c34..dd0c2ba
@@ -8,7 +8,8 @@ test_description='git-svn svk merge tickets'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svk depot' "
-       svnadmin load -q '$rawsvnrepo' < '../t9150/svk-merge.dump' &&
+       svnadmin load -q '$rawsvnrepo' \
+         < '$TEST_DIRECTORY/t9150/svk-merge.dump' &&
        git svn init --minimize-url -R svkmerge \
          -T trunk -b branches '$svnrepo' &&
        git svn fetch --all
old mode 100644 (file)
new mode 100755 (executable)
index 7eb36e5..9bee516
@@ -8,7 +8,8 @@ test_description='git-svn svn mergeinfo properties'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svn dump' "
-       svnadmin load -q '$rawsvnrepo' < '../t9151/svn-mergeinfo.dump' &&
+       svnadmin load -q '$rawsvnrepo' \
+         < '$TEST_DIRECTORY/t9151/svn-mergeinfo.dump' &&
        git svn init --minimize-url -R svnmerge \
          -T trunk -b branches '$svnrepo' &&
        git svn fetch --all
index 644a30a0b200b339d291f4cc3d35b2268d12facd..298dc46ec5ede0b972ec9be46556ffbec17df253 100644 (file)
@@ -812,6 +812,9 @@ struct transport *transport_get(struct remote *remote, const char *url)
 {
        struct transport *ret = xcalloc(1, sizeof(*ret));
 
+       if (!remote)
+               die("No remote provided to transport_get()");
+
        ret->remote = remote;
        ret->url = url;
 
@@ -849,10 +852,10 @@ struct transport *transport_get(struct remote *remote, const char *url)
                data->thin = 1;
                data->conn = NULL;
                data->uploadpack = "git-upload-pack";
-               if (remote && remote->uploadpack)
+               if (remote->uploadpack)
                        data->uploadpack = remote->uploadpack;
                data->receivepack = "git-receive-pack";
-               if (remote && remote->receivepack)
+               if (remote->receivepack)
                        data->receivepack = remote->receivepack;
        }