Merge branch 'mr/gitweb-jsmin'
authorJunio C Hamano <gitster@pobox.com>
Sat, 10 Apr 2010 20:02:22 +0000 (13:02 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 10 Apr 2010 20:02:22 +0000 (13:02 -0700)
* mr/gitweb-jsmin:
gitweb: update INSTALL to use shorter make target
gitweb: add documentation to INSTALL regarding gitweb.js
instaweb: add minification awareness
Gitweb: add autoconfigure support for minifiers
Gitweb: add support for minifying gitweb.css
Gitweb: add ignore and clean rules for minified files

81 files changed:
.mailmap
Documentation/RelNotes-1.7.1.txt
Documentation/everyday.txt
Documentation/git-branch.txt
Documentation/git-fetch.txt
Documentation/git-imap-send.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/howto/revert-a-faulty-merge.txt
Documentation/technical/api-string-list.txt
Documentation/technical/pack-protocol.txt
Makefile
branch.c
builtin/apply.c
builtin/checkout.c
builtin/commit.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/grep.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/mailinfo.c
builtin/merge-file.c
builtin/push.c
builtin/rev-list.c
builtin/revert.c
cache.h
contrib/ciabot/README [new file with mode: 0644]
contrib/ciabot/ciabot.py [new file with mode: 0755]
contrib/ciabot/ciabot.sh [new file with mode: 0755]
contrib/completion/git-completion.bash
contrib/fast-import/import-zips.py
contrib/hg-to-git/hg-to-git.py
contrib/p4import/git-p4import.py
daemon.c
diff.c
git-compat-util.h
git-rebase--interactive.sh
git-rebase.sh
git-send-email.perl
git-stash.sh
git.spec.in
git_remote_helpers/Makefile
grep.c
http-backend.c
imap-send.c
ll-merge.c
ll-merge.h
merge-file.c
merge-recursive.c
merge-recursive.h
notes.h
refs.c
rerere.c
sha1_file.c
string-list.c
string-list.h
submodule.c
t/t1304-default-acl.sh
t/t3301-notes.sh
t/t3404-rebase-interactive.sh
t/t3507-cherry-pick-conflict.sh [new file with mode: 0644]
t/t4017-diff-retval.sh
t/t4041-diff-submodule.sh
t/t5505-remote.sh
t/t6006-rev-list-format.sh
t/t6023-merge-file.sh
t/t6200-fmt-merge-msg.sh
t/t7201-co.sh
t/t7506-status-submodule.sh
templates/Makefile
templates/hooks--commit-msg.sample
templates/hooks--post-update.sample
templates/hooks--pre-commit.sample
templates/hooks--pre-rebase.sample
templates/hooks--prepare-commit-msg.sample
templates/hooks--update.sample
templates/info--exclude
xdiff/xdiff.h
xdiff/xmerge.c
index 88bd01e16d91f002cf3ac405e2a923884058d724..a8091eb5dfa430bf1b0537da47a31e7cf88d8622 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -5,6 +5,7 @@
 # same person appearing not to be so.
 #
 
+Alex Bennée <kernel-hacker@bennee.com>
 Alexander Gavrilov <angavrilov@gmail.com>
 Aneesh Kumar K.V <aneesh.kumar@gmail.com>
 Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
@@ -15,6 +16,7 @@ Daniel Barkalow <barkalow@iabervon.org>
 David D. Kilzer <ddkilzer@kilzer.net>
 David Kågedal <davidk@lysator.liu.se>
 David S. Miller <davem@davemloft.net>
+Deskin Miller <deskinm@umich.edu>
 Dirk Süsserott <newsletter@dirk.my1.cc>
 Fredrik Kuivinen <freku045@student.liu.se>
 H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
@@ -60,6 +62,7 @@ Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
 Uwe Kleine-König <uzeisberger@io.fsforth.de>
 Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
 Ville Skyttä <scop@xemacs.org>
+Vitaly "_Vi" Shukela <public_vi@tut.by>
 William Pursell <bill.pursell@gmail.com>
 YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
 anonymous <linux@horizon.com>
index 19aeef5effd16a7a7fc5409ca42bc54eb780e991..58cf113a90b0ebcebb0199a1ce1780d3a17f8a22 100644 (file)
@@ -4,16 +4,25 @@ Git v1.7.1 Release Notes (draft)
 Updates since v1.7.0
 --------------------
 
+ * Eric Raymond is the maintainer of updated CIAbot scripts, in contrib/.
+
  * Some commands (e.g. svn and http interfaces) that interactively ask
-   password can be told to use an external program given via GIT_ASKPASS.
+   for a password can be told to use an external program given via
+   GIT_ASKPASS.
+
+ * Conflict markers that lead the common ancestor in diff3-style output
+   now have a label, which hopefully would help third-party tools that
+   expect one.
+
+ * Comes with an updated bash-completion script.
 
  * "git am" learned "--keep-cr" option to handle inputs that are
-   mixture of changes to files with and without CRLF line endings.
+   mixture of changes to files with and without CRLF line endings.
 
  * "git cvsimport" learned -R option to leave revision mapping between
    CVS revisions and resulting git commits.
 
- * "git diff --submodule" notices and descries dirty submodules.
+ * "git diff --submodule" notices and describes dirty submodules.
 
  * "git for-each-ref" learned %(symref), %(symref:short) and %(flag)
    tokens.
@@ -34,12 +43,11 @@ Updates since v1.7.0
  * "git log -p --first-parent -m" shows one-parent diff for merge
    commits, instead of showing combined diff.
 
- * "git merge-file" learned to use custom conflict marker size and also use
-   the "union merge" behaviour.
+ * "git merge-file" learned to use custom conflict marker size and also
+   to use the "union merge" behaviour.
 
- * "git notes" command has been rewritten in C and learned quite a
-   many commands and features to help you carry notes forward across
-   rebases and amends.
+ * "git notes" command has been rewritten in C and learned many commands
+   and features to help you carry notes forward across rebases and amends.
 
  * "git request-pull" identifies the commit the request is relative to in
    a more readable way.
@@ -48,7 +56,7 @@ Updates since v1.7.0
    near the tip while preserving your local changes in a way similar
    to how "git checkout branch" does.
 
- * "git status" notices and descries dirty submodules.
+ * "git status" notices and describes dirty submodules.
 
  * "git svn" should work better when interacting with repositories
    with CRLF line endings.
@@ -64,8 +72,14 @@ release, unless otherwise noted.
  * "git add frotz/nitfol" did not complain when the entire frotz/ directory
    was ignored.
 
+ * "git rev-list --pretty=oneline" didn't terminate a record with LF for
+   commits without any message.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+   newer tools in the git toolset.
+
 ---
 exec >/var/tmp/1
 echo O=$(git describe)
-O=v1.7.0.3-310-g99f5b08
+O=v1.7.0.4-382-gb807c52
 git shortlog --no-merges ^maint $O..
index 9310b650d3ca6b6cb7d69814eb9b800e8c2c85cd..e0ba8cc07549af375c89496c57c016a41b8cc699 100644 (file)
@@ -1,13 +1,8 @@
 Everyday GIT With 20 Commands Or So
 ===================================
 
-<<Basic Repository>> commands are needed by people who have a
-repository --- that is everybody, because every working tree of
-git is a repository.
-
-In addition, <<Individual Developer (Standalone)>> commands are
-essential for anybody who makes a commit, even for somebody who
-works alone.
+<<Individual Developer (Standalone)>> commands are essential for
+anybody who makes a commit, even for somebody who works alone.
 
 If you work with other people, you will need commands listed in
 the <<Individual Developer (Participant)>> section as well.
@@ -20,46 +15,6 @@ administrators who are responsible for the care and feeding
 of git repositories.
 
 
-Basic Repository[[Basic Repository]]
-------------------------------------
-
-Everybody uses these commands to maintain git repositories.
-
-  * linkgit:git-init[1] or linkgit:git-clone[1] to create a
-    new repository.
-
-  * linkgit:git-fsck[1] to check the repository for errors.
-
-  * linkgit:git-gc[1] to do common housekeeping tasks such as
-    repack and prune.
-
-Examples
-~~~~~~~~
-
-Check health and remove cruft.::
-+
-------------
-$ git fsck <1>
-$ git count-objects <2>
-$ git gc <3>
-------------
-+
-<1> running without `\--full` is usually cheap and assures the
-repository health reasonably well.
-<2> check how many loose objects there are and how much
-disk space is wasted by not repacking.
-<3> repacks the local repository and performs other housekeeping tasks.
-
-Repack a small project into single pack.::
-+
-------------
-$ git gc <1>
-------------
-+
-<1> pack all the objects reachable from the refs into one pack,
-then remove the other packs.
-
-
 Individual Developer (Standalone)[[Individual Developer (Standalone)]]
 ----------------------------------------------------------------------
 
@@ -67,6 +22,8 @@ A standalone individual developer does not exchange patches with
 other people, and works alone in a single repository, using the
 following commands.
 
+  * linkgit:git-init[1] to create a new repository.
+
   * linkgit:git-show-branch[1] to see where you are.
 
   * linkgit:git-log[1] to see what happened.
index 903a690f10e3cdb7aea15a19332bf0e8bc87814e..d78f4c7398be1e7a403fcc34a9587dfee651b72d 100644 (file)
@@ -72,6 +72,8 @@ OPTIONS
        Create the branch's reflog.  This activates recording of
        all changes made to the branch ref, enabling use of date
        based sha1 expressions such as "<branchname>@\{yesterday}".
+       Note that in non-bare repositories, reflogs are usually
+       enabled by default by the `core.logallrefupdates` config option.
 
 -f::
 --force::
index 948ea26c5a2b3825e61d0c6495d03829669a7351..400fe7f956961ba0ddf09d2dcc6e539adec7ff74 100644 (file)
@@ -8,13 +8,13 @@ git-fetch - Download objects and refs from another repository
 
 SYNOPSIS
 --------
-'git fetch' <options> <repository> <refspec>...
+'git fetch' [<options>] [<repository> [<refspec>...]]
 
-'git fetch' <options> <group>
+'git fetch' [<options>] <group>
 
-'git fetch' --multiple <options> [<repository> | <group>]...
+'git fetch' --multiple [<options>] [<repository> | <group>]...
 
-'git fetch' --all <options>
+'git fetch' --all [<options>]
 
 
 DESCRIPTION
index 6cafbe2ec191b2e2b35e7855c71837fa0f231785..57aba42e6654e3d32617c3c7b17d18e8dd85852b 100644 (file)
@@ -16,7 +16,9 @@ DESCRIPTION
 This command uploads a mailbox generated with 'git format-patch'
 into an IMAP drafts folder.  This allows patches to be sent as
 other email is when using mail clients that cannot read mailbox
-files directly.
+files directly. The command also works with any general mailbox
+in which emails have the fields "From", "Date", and "Subject" in
+that order.
 
 Typical usage is something like:
 
@@ -122,12 +124,6 @@ Thunderbird in particular is known to be problematic.  Thunderbird
 users may wish to visit this web page for more information:
   http://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
 
-
-BUGS
-----
-Doesn't handle lines starting with "From " in the message body.
-
-
 Author
 ------
 Derived from isync 1.0.1 by Mike McCormack.
index 59dc8b197ecb4b6912c9ec29f83f21c405ef8634..48570242fb2dda31a5684e2d678d40690d3c4cab 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
           [--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream]
-          [<repository> <refspec>...]
+          [<repository> [<refspec>...]]
 
 DESCRIPTION
 -----------
index 823f2a4638c5b53671e294faf7a99a56d17c897a..0d07b1b2077c62f1199c5ee96790e5a7121b4f00 100644 (file)
@@ -274,9 +274,16 @@ which makes little sense.
 -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
+       of the commit you are rebasing onto.  Normally non-interactive rebase will
        exit with the message "Current branch is up to date" in such a
        situation.
+       Incompatible with the --interactive option.
++
+You may find this (or --no-ff with an interactive rebase) helpful after
+reverting a topic branch merge, as this option recreates the topic branch with
+fresh commits so it can be remerged successfully without needing to "revert
+the reversion" (see the
+link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
 
 --ignore-whitespace::
 --whitespace=<option>::
@@ -316,7 +323,19 @@ which makes little sense.
        commit to be modified, and change the action of the moved
        commit from `pick` to `squash` (or `fixup`).
 +
-This option is only valid when '--interactive' option is used.
+This option is only valid when the '--interactive' option is used.
+
+--no-ff::
+       With --interactive, cherry-pick all rebased commits instead of
+       fast-forwarding over the unchanged ones.  This ensures that the
+       entire history of the rebased branch is composed of new commits.
++
+Without --interactive, this is a synonym for --force-rebase.
++
+You may find this helpful after reverting a topic branch merge, as this option
+recreates the topic branch with fresh commits so it can be remerged
+successfully without needing to "revert the reversion" (see the
+link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
 
 include::merge-strategies.txt[]
 
index 3b4a390005b07c86ee320ee8ca1cf57e46458cb6..ff5c0bc27a416de16f106c15b9076082c6509e42 100644 (file)
@@ -142,6 +142,8 @@ different resolution strategies:
    revert of a merge was rebuilt from scratch (i.e. rebasing and fixing,
    as you seem to have interpreted), then re-merging the result without
    doing anything else fancy would be the right thing to do.
+   (See the ADDENDUM below for how to rebuild a branch from scratch
+   without changing its original branching-off point.)
 
 However, there are things to keep in mind when reverting a merge (and
 reverting such a revert).
@@ -177,3 +179,91 @@ the answer is: "oops, I really shouldn't have merged it, because it wasn't
 ready yet, and I really need to undo _all_ of the merge"). So then you
 really should revert the merge, but when you want to re-do the merge, you
 now need to do it by reverting the revert.
+
+ADDENDUM
+
+Sometimes you have to rewrite one of a topic branch's commits *and* you can't
+change the topic's branching-off point.  Consider the following situation:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C
+
+where commit W reverted commit M because it turned out that commit B was wrong
+and needs to be rewritten, but you need the rewritten topic to still branch
+from commit P (perhaps P is a branching-off point for yet another branch, and
+you want be able to merge the topic into both branches).
+
+The natural thing to do in this case is to checkout the A-B-C branch and use
+"rebase -i P" to change commit B.  However this does not rewrite commit A,
+because "rebase -i" by default fast-forwards over any initial commits selected
+with the "pick" command.  So you end up with this:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C   <-- old branch
+    \
+     B'---C'   <-- naively rewritten branch
+
+To merge A-B'-C' into the mainline branch you would still have to first revert
+commit W in order to pick up the changes in A, but then it's likely that the
+changes in B' will conflict with the original B changes re-introduced by the
+reversion of W.
+
+However, you can avoid these problems if you recreate the entire branch,
+including commit A:
+
+   A'---B'---C'  <-- completely rewritten branch
+  /
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C
+
+You can merge A'-B'-C' into the mainline branch without worrying about first
+reverting W.  Mainline's history would look like this:
+
+   A'---B'---C'------------------
+  /                              \
+ P---o---o---M---x---x---W---x---M2
+  \         /
+   A---B---C
+
+But if you don't actually need to change commit A, then you need some way to
+recreate it as a new commit with the same changes in it.  The rebase commmand's
+--no-ff option provides a way to do this:
+
+    $ git rebase [-i] --no-ff P
+
+The --no-ff option creates a new branch A'-B'-C' with all-new commits (all the
+SHA IDs will be different) even if in the interactive case you only actually
+modify commit B.  You can then merge this new branch directly into the mainline
+branch and be sure you'll get all of the branch's changes.
+
+You can also use --no-ff in cases where you just add extra commits to the topic
+to fix it up.  Let's revisit the situation discussed at the start of this howto:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C----------------D---E   <-- fixed-up topic branch
+
+At this point, you can use --no-ff to recreate the topic branch:
+
+    $ git checkout E
+    $ git rebase --no-ff P
+
+yielding
+
+   A'---B'---C'------------D'---E'  <-- recreated topic branch
+  /
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C----------------D---E
+
+You can merge the recreated branch into the mainline without reverting commit W,
+and mainline's history will look like this:
+
+   A'---B'---C'------------D'---E'
+  /                              \
+ P---o---o---M---x---x---W---x---M2
+  \         /
+   A---B---C
index 293bb15d206e71f57e906b33ca27ee05e3429521..6d8c24bb1e68e86d70d4a68d02e3a4d5ccb94c2a 100644 (file)
@@ -104,8 +104,12 @@ write `string_list_insert(...)->util = ...;`.
 `unsorted_string_list_has_string`::
 
        It's like `string_list_has_string()` but for unsorted lists.
+
+`unsorted_string_list_lookup`::
+
+       It's like `string_list_lookup()` but for unsorted lists.
 +
-This function needs to look through all items, as opposed to its
+The above two functions need to look through all items, as opposed to their
 counterpart for sorted lists, which performs a binary search.
 
 Data structures
index 9a5cdafa9cb8c5af8a3903ae18297a23adab0fbf..369f91d3b949b23682c4deda8234f13513f15732 100644 (file)
@@ -36,7 +36,7 @@ Git Transport
 
 The Git transport starts off by sending the command and repository
 on the wire using the pkt-line format, followed by a NUL byte and a
-hostname paramater, terminated by a NUL byte.
+hostname parameter, terminated by a NUL byte.
 
    0032git-upload-pack /project.git\0host=myserver.com\0
 
@@ -331,7 +331,7 @@ An incremental update (fetch) response might look like this:
 
    C: 0009done\n
 
-   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
    S: [PACKFILE]
 ----
 
@@ -488,7 +488,7 @@ An example client/server communication might look like this:
    C: 0000
    C: [PACKDATA]
 
-   S: 000aunpack ok\n
-   S: 0014ok refs/heads/debug\n
-   S: 0026ng refs/heads/master non-fast-forward\n
+   S: 000eunpack ok\n
+   S: 0018ok refs/heads/debug\n
+   S: 002ang refs/heads/master non-fast-forward\n
 ----
index 7aad43fd2482af434d5e67b30d289e1a5e1ffa0e..910f4713ef1491278500573bab2d00ee1925abb8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ all::
 # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
 #
 # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
-# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
+# d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7).
 #
 # Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
 # do not support the 'size specifiers' introduced by C99, namely ll, hh,
@@ -109,7 +109,7 @@ all::
 # Define NO_PTHREADS if you do not have or do not want to use Pthreads.
 #
 # Define NO_PREAD if you have a problem with pread() system call (e.g.
-# cygwin.dll before v1.5.22).
+# cygwin1.dll before v1.5.22).
 #
 # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
 # generally faster on your platform than accessing the working directory.
@@ -831,22 +831,24 @@ ifeq ($(uname_S),SunOS)
        BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
 endif
 ifeq ($(uname_O),Cygwin)
-       NO_D_TYPE_IN_DIRENT = YesPlease
-       NO_D_INO_IN_DIRENT = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_SYMLINK_HEAD = YesPlease
+       ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
+               NO_D_TYPE_IN_DIRENT = YesPlease
+               NO_D_INO_IN_DIRENT = YesPlease
+               NO_STRCASESTR = YesPlease
+               NO_MEMMEM = YesPlease
+               NO_MKSTEMPS = YesPlease
+               NO_SYMLINK_HEAD = YesPlease
+               NO_IPV6 = YesPlease
+               OLD_ICONV = UnfortunatelyYes
+       endif
        NEEDS_LIBICONV = YesPlease
        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
        NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
-       OLD_ICONV = UnfortunatelyYes
        NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
        # There are conflicting reports about this.
        # On some boxes NO_MMAP is needed, and not so elsewhere.
        # Try commenting this out if you suspect MMAP is more efficient
        NO_MMAP = YesPlease
-       NO_IPV6 = YesPlease
        X = .exe
        COMPAT_OBJS += compat/cygwin.o
        UNRELIABLE_FSTAT = UnfortunatelyYes
@@ -864,6 +866,7 @@ ifeq ($(uname_S),FreeBSD)
                NO_UINTMAX_T = YesPlease
                NO_STRTOUMAX = YesPlease
        endif
+       PYTHON_PATH = /usr/local/bin/python
 endif
 ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
@@ -919,7 +922,6 @@ ifeq ($(uname_S),IRIX)
        SNPRINTF_RETURNS_BOGUS = YesPlease
        SHELL_PATH = /usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
-       NEEDS_LIBICONV = YesPlease
 endif
 ifeq ($(uname_S),IRIX64)
        NO_SETENV=YesPlease
@@ -938,7 +940,6 @@ ifeq ($(uname_S),IRIX64)
        SNPRINTF_RETURNS_BOGUS = YesPlease
        SHELL_PATH=/usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
-       NEEDS_LIBICONV = YesPlease
 endif
 ifeq ($(uname_S),HP-UX)
        NO_IPV6=YesPlease
@@ -1478,7 +1479,7 @@ endif
 ifndef NO_PYTHON
        $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
 endif
-       $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
+       $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
 
 please_set_SHELL_PATH_to_a_more_modern_shell:
        @$$(:)
@@ -1624,9 +1625,8 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
            -e '}' \
            -e 's|^import sys.*|&; \\\
                   import os; \\\
-                  sys.path[0] = os.environ.has_key("GITPYTHONLIB") and \\\
-                                os.environ["GITPYTHONLIB"] or \\\
-                                "@@INSTLIBDIR@@"|' \
+                  sys.path.insert(0, os.getenv("GITPYTHONLIB",\
+                                               "@@INSTLIBDIR@@"));|' \
            -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
            $@.py >$@+ && \
        chmod +x $@+ && \
index 9e1f63ed8dbe8b087f99292880059642d9744697..2ab42aaf4da38b4ea45ef7f0a0f6b807313d4a22 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -198,7 +198,7 @@ void create_branch(const char *head,
                log_all_ref_updates = 1;
 
        if (forcing)
-               snprintf(msg, sizeof msg, "branch: Reset from %s",
+               snprintf(msg, sizeof msg, "branch: Reset to %s",
                         start_name);
        else if (!dont_change_ref)
                snprintf(msg, sizeof msg, "branch: Created from %s",
index 7ca90472c10eed8535e76b1e0ec25c92af7cff05..771c972c5506db4848e2c214fb617525bafdf335 100644 (file)
@@ -2824,11 +2824,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                if (stat_ret < 0) {
                        struct checkout costate;
                        /* checkout */
+                       memset(&costate, 0, sizeof(costate));
                        costate.base_dir = "";
-                       costate.base_dir_len = 0;
-                       costate.force = 0;
-                       costate.quiet = 0;
-                       costate.not_new = 0;
                        costate.refresh_cache = 1;
                        if (checkout_entry(*ce, &costate, NULL) ||
                            lstat(old_name, st))
index acefaaf41a4e26e45225f6d228734c93c8f2b23c..88b1f43e05e64f0e8dcd6dd0461bbebd6fab1e25 100644 (file)
@@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state)
        read_mmblob(&ours, active_cache[pos+1]->sha1);
        read_mmblob(&theirs, active_cache[pos+2]->sha1);
 
-       status = ll_merge(&result_buf, path, &ancestor,
+       status = ll_merge(&result_buf, path, &ancestor, "base",
                          &ours, "ours", &theirs, "theirs", 0);
        free(ancestor.ptr);
        free(ours.ptr);
@@ -439,6 +439,7 @@ static int merge_working_tree(struct checkout_opts *opts,
                        ret = reset_tree(new->commit->tree, opts, 1);
                        if (ret)
                                return ret;
+                       o.ancestor = old->name;
                        o.branch1 = new->name;
                        o.branch2 = "local";
                        merge_trees(&o, new->commit->tree, work,
index 8dd104ee0b247f5536d02d54a932acfcbaec603b..c5ab683d5b66d5ad85f53d13d6df71e29cd9234d 100644 (file)
@@ -307,7 +307,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         * (B) on failure, rollback the real index.
         */
        if (all || (also && pathspec && *pathspec)) {
-               int fd = hold_locked_index(&index_lock, 1);
+               fd = hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
@@ -322,8 +322,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         *
         * (1) return the name of the real index file.
         *
-        * The caller should run hooks on the real index, and run
-        * hooks on the real index, and create commit from the_index.
+        * The caller should run hooks on the real index,
+        * and create commit from the_index.
         * We still need to refresh the index here.
         */
        if (!pathspec || !*pathspec) {
index 957be9f9269c657fb094b1b3daa4f309c1324ae0..8470850415c14cad8ceeca9f6baef46ab6feabc3 100644 (file)
 #include "transport.h"
 
 static const char * const builtin_fetch_usage[] = {
-       "git fetch [options] [<repository> <refspec>...]",
-       "git fetch [options] <group>",
-       "git fetch --multiple [options] [<repository> | <group>]...",
-       "git fetch --all [options]",
+       "git fetch [<options>] [<repository> [<refspec>...]]",
+       "git fetch [<options>] <group>",
+       "git fetch --multiple [<options>] [<repository> | <group>]...",
+       "git fetch --all [<options>]",
        NULL
 };
 
index 9d524000b5ba4d9c7566edd5756b68d728ec362b..379a03131fbd84fb2b45a6b05e62daf82b7e4947 100644 (file)
@@ -4,6 +4,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "tag.h"
+#include "string-list.h"
 
 static const char * const fmt_merge_msg_usage[] = {
        "git fmt-merge-msg [--log|--no-log] [--file <file>]",
@@ -24,58 +25,21 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
        return 0;
 }
 
-struct list {
-       char **list;
-       void **payload;
-       unsigned nr, alloc;
+struct src_data {
+       struct string_list branch, tag, r_branch, generic;
+       int head_status;
 };
 
-static void append_to_list(struct list *list, char *value, void *payload)
-{
-       if (list->nr == list->alloc) {
-               list->alloc += 32;
-               list->list = xrealloc(list->list, sizeof(char *) * list->alloc);
-               list->payload = xrealloc(list->payload,
-                               sizeof(char *) * list->alloc);
-       }
-       list->payload[list->nr] = payload;
-       list->list[list->nr++] = value;
-}
-
-static int find_in_list(struct list *list, char *value)
-{
-       int i;
-
-       for (i = 0; i < list->nr; i++)
-               if (!strcmp(list->list[i], value))
-                       return i;
-
-       return -1;
-}
-
-static void free_list(struct list *list)
+void init_src_data(struct src_data *data)
 {
-       int i;
-
-       if (list->alloc == 0)
-               return;
-
-       for (i = 0; i < list->nr; i++) {
-               free(list->list[i]);
-               free(list->payload[i]);
-       }
-       free(list->list);
-       free(list->payload);
-       list->nr = list->alloc = 0;
+       data->branch.strdup_strings = 1;
+       data->tag.strdup_strings = 1;
+       data->r_branch.strdup_strings = 1;
+       data->generic.strdup_strings = 1;
 }
 
-struct src_data {
-       struct list branch, tag, r_branch, generic;
-       int head_status;
-};
-
-static struct list srcs = { NULL, NULL, 0, 0};
-static struct list origins = { NULL, NULL, 0, 0};
+static struct string_list srcs = { NULL, 0, 0, 1 };
+static struct string_list origins = { NULL, 0, 0, 1 };
 
 static int handle_line(char *line)
 {
@@ -83,6 +47,7 @@ static int handle_line(char *line)
        unsigned char *sha1;
        char *src, *origin;
        struct src_data *src_data;
+       struct string_list_item *item;
        int pulling_head = 0;
 
        if (len < 43 || line[40] != '\t')
@@ -115,64 +80,62 @@ static int handle_line(char *line)
                pulling_head = 1;
        }
 
-       i = find_in_list(&srcs, src);
-       if (i < 0) {
-               i = srcs.nr;
-               append_to_list(&srcs, xstrdup(src),
-                               xcalloc(1, sizeof(struct src_data)));
+       item = unsorted_string_list_lookup(&srcs, src);
+       if (!item) {
+               item = string_list_append(src, &srcs);
+               item->util = xcalloc(1, sizeof(struct src_data));
+               init_src_data(item->util);
        }
-       src_data = srcs.payload[i];
+       src_data = item->util;
 
        if (pulling_head) {
-               origin = xstrdup(src);
+               origin = src;
                src_data->head_status |= 1;
        } else if (!prefixcmp(line, "branch ")) {
-               origin = xstrdup(line + 7);
-               append_to_list(&src_data->branch, origin, NULL);
+               origin = line + 7;
+               string_list_append(origin, &src_data->branch);
                src_data->head_status |= 2;
        } else if (!prefixcmp(line, "tag ")) {
                origin = line;
-               append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
+               string_list_append(origin + 4, &src_data->tag);
                src_data->head_status |= 2;
        } else if (!prefixcmp(line, "remote branch ")) {
-               origin = xstrdup(line + 14);
-               append_to_list(&src_data->r_branch, origin, NULL);
+               origin = line + 14;
+               string_list_append(origin, &src_data->r_branch);
                src_data->head_status |= 2;
        } else {
-               origin = xstrdup(src);
-               append_to_list(&src_data->generic, xstrdup(line), NULL);
+               origin = src;
+               string_list_append(line, &src_data->generic);
                src_data->head_status |= 2;
        }
 
        if (!strcmp(".", src) || !strcmp(src, origin)) {
                int len = strlen(origin);
-               if (origin[0] == '\'' && origin[len - 1] == '\'') {
+               if (origin[0] == '\'' && origin[len - 1] == '\'')
                        origin = xmemdupz(origin + 1, len - 2);
-               } else {
-                       origin = xstrdup(origin);
-               }
        } else {
                char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
                sprintf(new_origin, "%s of %s", origin, src);
                origin = new_origin;
        }
-       append_to_list(&origins, origin, sha1);
+       string_list_append(origin, &origins)->util = sha1;
        return 0;
 }
 
 static void print_joined(const char *singular, const char *plural,
-               struct list *list, struct strbuf *out)
+               struct string_list *list, struct strbuf *out)
 {
        if (list->nr == 0)
                return;
        if (list->nr == 1) {
-               strbuf_addf(out, "%s%s", singular, list->list[0]);
+               strbuf_addf(out, "%s%s", singular, list->items[0].string);
        } else {
                int i;
                strbuf_addstr(out, plural);
                for (i = 0; i < list->nr - 1; i++)
-                       strbuf_addf(out, "%s%s", i > 0 ? ", " : "", list->list[i]);
-               strbuf_addf(out, " and %s", list->list[list->nr - 1]);
+                       strbuf_addf(out, "%s%s", i > 0 ? ", " : "",
+                                   list->items[i].string);
+               strbuf_addf(out, " and %s", list->items[list->nr - 1].string);
        }
 }
 
@@ -183,8 +146,9 @@ static void shortlog(const char *name, unsigned char *sha1,
        int i, count = 0;
        struct commit *commit;
        struct object *branch;
-       struct list subjects = { NULL, NULL, 0, 0 };
+       struct string_list subjects = { NULL, 0, 0, 1 };
        int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
+       struct strbuf sb = STRBUF_INIT;
 
        branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
        if (!branch || branch->type != OBJ_COMMIT)
@@ -198,7 +162,7 @@ static void shortlog(const char *name, unsigned char *sha1,
        if (prepare_revision_walk(rev))
                die("revision walk setup failed");
        while ((commit = get_revision(rev)) != NULL) {
-               char *oneline, *bol, *eol;
+               struct pretty_print_context ctx = {0};
 
                /* ignore merges */
                if (commit->parents && commit->parents->next)
@@ -208,30 +172,14 @@ static void shortlog(const char *name, unsigned char *sha1,
                if (subjects.nr > limit)
                        continue;
 
-               bol = strstr(commit->buffer, "\n\n");
-               if (bol) {
-                       unsigned char c;
-                       do {
-                               c = *++bol;
-                       } while (isspace(c));
-                       if (!c)
-                               bol = NULL;
-               }
-
-               if (!bol) {
-                       append_to_list(&subjects, xstrdup(sha1_to_hex(
-                                                       commit->object.sha1)),
-                                       NULL);
-                       continue;
-               }
+               format_commit_message(commit, "%s", &sb, &ctx);
+               strbuf_ltrim(&sb);
 
-               eol = strchr(bol, '\n');
-               if (eol) {
-                       oneline = xmemdupz(bol, eol - bol);
-               } else {
-                       oneline = xstrdup(bol);
-               }
-               append_to_list(&subjects, oneline, NULL);
+               if (!sb.len)
+                       string_list_append(sha1_to_hex(commit->object.sha1),
+                                          &subjects);
+               else
+                       string_list_append(strbuf_detach(&sb, NULL), &subjects);
        }
 
        if (count > limit)
@@ -243,7 +191,7 @@ static void shortlog(const char *name, unsigned char *sha1,
                if (i >= limit)
                        strbuf_addf(out, "  ...\n");
                else
-                       strbuf_addf(out, "  %s\n", subjects.list[i]);
+                       strbuf_addf(out, "  %s\n", subjects.items[i].string);
 
        clear_commit_marks((struct commit *)branch, flags);
        clear_commit_marks(head, flags);
@@ -251,7 +199,7 @@ static void shortlog(const char *name, unsigned char *sha1,
        rev->commits = NULL;
        rev->pending.nr = 0;
 
-       free_list(&subjects);
+       string_list_clear(&subjects, 0);
 }
 
 int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
@@ -281,16 +229,19 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
                        die ("Error in line %d: %.*s", i, len, p);
        }
 
+       if (!srcs.nr)
+               return 0;
+
        strbuf_addstr(out, "Merge ");
        for (i = 0; i < srcs.nr; i++) {
-               struct src_data *src_data = srcs.payload[i];
+               struct src_data *src_data = srcs.items[i].util;
                const char *subsep = "";
 
                strbuf_addstr(out, sep);
                sep = "; ";
 
                if (src_data->head_status == 1) {
-                       strbuf_addstr(out, srcs.list[i]);
+                       strbuf_addstr(out, srcs.items[i].string);
                        continue;
                }
                if (src_data->head_status == 3) {
@@ -319,8 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
                        print_joined("commit ", "commits ", &src_data->generic,
                                        out);
                }
-               if (strcmp(".", srcs.list[i]))
-                       strbuf_addf(out, " of %s", srcs.list[i]);
+               if (strcmp(".", srcs.items[i].string))
+                       strbuf_addf(out, " of %s", srcs.items[i].string);
        }
 
        if (!strcmp("master", current_branch))
@@ -339,7 +290,7 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
                rev.limited = 1;
 
                for (i = 0; i < origins.nr; i++)
-                       shortlog(origins.list[i], origins.payload[i],
+                       shortlog(origins.items[i].string, origins.items[i].util,
                                        head, &rev, limit, out);
        }
        return 0;
@@ -350,7 +301,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        const char *inpath = NULL;
        struct option options[] = {
                OPT_BOOLEAN(0, "log",     &merge_summary, "populate log with the shortlog"),
-               OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
+               { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL,
+                 "alias for --log (deprecated)",
+                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_FILENAME('F', "file", &inpath, "file to read from"),
                OPT_END()
        };
index 9d30ddb28df16f834c9fbb3bf6ba8cc172a502b3..8e928e217041a159f4a962f0883d740aa84536d7 100644 (file)
@@ -96,6 +96,9 @@ static pthread_cond_t cond_write;
 /* Signalled when we are finished with everything. */
 static pthread_cond_t cond_result;
 
+static int print_hunk_marks_between_files;
+static int printed_something;
+
 static void add_work(enum work_type type, char *name, void *id)
 {
        grep_lock();
@@ -159,7 +162,12 @@ static void work_done(struct work_item *w)
        for(; todo[todo_done].done && todo_done != todo_start;
            todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
                w = &todo[todo_done];
-               write_or_die(1, w->out.buf, w->out.len);
+               if (w->out.len) {
+                       if (print_hunk_marks_between_files && printed_something)
+                               write_or_die(1, "--\n", 3);
+                       write_or_die(1, w->out.buf, w->out.len);
+                       printed_something = 1;
+               }
                free(w->name);
                free(w->identifier);
        }
@@ -946,8 +954,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (online_cpus() == 1 || !grep_threads_ok(&opt))
                use_threads = 0;
 
-       if (use_threads)
+       if (use_threads) {
+               if (opt.pre_context || opt.post_context)
+                       print_hunk_marks_between_files = 1;
                start_threads(&opt);
+       }
 #else
        use_threads = 0;
 #endif
index 542ecc708bdb830bcdbbd48e3fb3d21021119630..b706a5ff88ec185e63c0aacd109bb16cc54027e3 100644 (file)
@@ -1303,8 +1303,11 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
        return -1;
 }
 
-static const char cherry_usage[] =
-"git cherry [-v] [<upstream> [<head> [<limit>]]]";
+static const char * const cherry_usage[] = {
+       "git cherry [-v] [<upstream> [<head> [<limit>]]]",
+       NULL
+};
+
 int cmd_cherry(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
@@ -1315,26 +1318,25 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
        const char *upstream;
        const char *head = "HEAD";
        const char *limit = NULL;
-       int verbose = 0;
+       int verbose = 0, abbrev = 0;
 
-       if (argc > 1 && !strcmp(argv[1], "-v")) {
-               verbose = 1;
-               argc--;
-               argv++;
-       }
+       struct option options[] = {
+               OPT__ABBREV(&abbrev),
+               OPT__VERBOSE(&verbose),
+               OPT_END()
+       };
 
-       if (argc > 1 && !strcmp(argv[1], "-h"))
-               usage(cherry_usage);
+       argc = parse_options(argc, argv, prefix, options, cherry_usage, 0);
 
        switch (argc) {
-       case 4:
-               limit = argv[3];
-               /* FALLTHROUGH */
        case 3:
-               head = argv[2];
+               limit = argv[2];
                /* FALLTHROUGH */
        case 2:
-               upstream = argv[1];
+               head = argv[1];
+               /* FALLTHROUGH */
+       case 1:
+               upstream = argv[0];
                break;
        default:
                current_branch = branch_get(NULL);
@@ -1344,7 +1346,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                        fprintf(stderr, "Could not find a tracked"
                                        " remote branch, please"
                                        " specify <upstream> manually.\n");
-                       usage(cherry_usage);
+                       usage_with_options(cherry_usage, options);
                }
 
                upstream = current_branch->merge[0]->dst;
@@ -1397,12 +1399,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                        pretty_print_commit(CMIT_FMT_ONELINE, commit,
                                            &buf, &ctx);
                        printf("%c %s %s\n", sign,
-                              sha1_to_hex(commit->object.sha1), buf.buf);
+                              find_unique_abbrev(commit->object.sha1, abbrev),
+                              buf.buf);
                        strbuf_release(&buf);
                }
                else {
                        printf("%c %s\n", sign,
-                              sha1_to_hex(commit->object.sha1));
+                              find_unique_abbrev(commit->object.sha1, abbrev));
                }
 
                list = list->next;
index b065061392718e4250d2c52dc3d53a0c1c7938e9..c0fbcdcf4f3447c29c4058907ea2e25fa6d225a6 100644 (file)
@@ -153,8 +153,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
                printf("%s%06o %s %d\t",
                       tag,
                       ce->ce_mode,
-                      abbrev ? find_unique_abbrev(ce->sha1,abbrev)
-                               : sha1_to_hex(ce->sha1),
+                      find_unique_abbrev(ce->sha1,abbrev),
                       ce_stage(ce));
        }
        write_name_quoted(ce->name + offset, stdout, line_terminator);
@@ -176,9 +175,7 @@ static int show_one_ru(struct string_list_item *item, void *cbdata)
                if (!ui->mode[i])
                        continue;
                printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
-                      abbrev
-                      ? find_unique_abbrev(ui->sha1[i], abbrev)
-                      : sha1_to_hex(ui->sha1[i]),
+                      find_unique_abbrev(ui->sha1[i], abbrev),
                       i + 1);
                write_name_quoted(path + offset, stdout, line_terminator);
        }
index 4484185afc4c144bc0d88d9c3832cbeb1515841b..dc86b0d9a997f98ad43ca2897055a92b8a3eb7d0 100644 (file)
@@ -103,13 +103,11 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
                        } else
                                strcpy(size_text, "-");
                        printf("%06o %s %s %7s\t", mode, type,
-                              abbrev ? find_unique_abbrev(sha1, abbrev)
-                                     : sha1_to_hex(sha1),
+                              find_unique_abbrev(sha1, abbrev),
                               size_text);
                } else
                        printf("%06o %s %s\t", mode, type,
-                              abbrev ? find_unique_abbrev(sha1, abbrev)
-                                     : sha1_to_hex(sha1));
+                              find_unique_abbrev(sha1, abbrev));
        }
        write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
                          pathname, stdout, line_termination);
index ce2ef6bede40fde8823336bc85762bd3e7cd4760..4a9729b9b388a1e589e9250d8157e723c68140de 100644 (file)
@@ -746,7 +746,8 @@ static int is_scissors_line(const struct strbuf *line)
                        continue;
                }
                if (i + 1 < len &&
-                   (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) {
+                   (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) ||
+                    !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) {
                        in_perforation = 1;
                        perforation += 2;
                        scissors += 2;
index 69cc683332a04ddc6959fcef3d2853ccfb2860b8..610849a6533c6fd2d3d2e8d3f8d233757174aabd 100644 (file)
@@ -77,8 +77,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
                                        argv[i]);
        }
 
-       ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
-                       &xmp, &result);
+       xmp.ancestor = names[1];
+       xmp.file1 = names[0];
+       xmp.file2 = names[2];
+       ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
 
        for (i = 0; i < 3; i++)
                free(mmfs[i].ptr);
index 62957ededdf72b93f088586f5d577ef8d38a7f6c..f4358b9d230f6d8d7a9a67fdfbc60279c5ec71ee 100644 (file)
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-       "git push [<options>] [<repository> <refspec>...]",
+       "git push [<options>] [<repository> [<refspec>...]]",
        NULL,
 };
 
index 5679170e82ed644d4c3eb4f71f26aa0ac9acce24..51ceb19d88918445c90eccc37f1fe5f90cedd385 100644 (file)
@@ -133,9 +133,12 @@ static void show_commit(struct commit *commit, void *data)
                                 */
                                if (graph_show_remainder(revs->graph))
                                        putchar('\n');
+                               if (revs->commit_format == CMIT_FMT_ONELINE)
+                                       putchar('\n');
                        }
                } else {
-                       if (buf.len)
+                       if (revs->commit_format != CMIT_FMT_USERFORMAT ||
+                           buf.len)
                                printf("%s%c", buf.buf, info->hdr_termination);
                }
                strbuf_release(&buf);
@@ -313,7 +316,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 
        git_config(git_default_config, NULL);
        init_revisions(&revs, prefix);
-       revs.abbrev = 0;
+       revs.abbrev = DEFAULT_ABBREV;
        revs.commit_format = CMIT_FMT_UNSPECIFIED;
        argc = setup_revisions(argc, argv, &revs, NULL);
 
index 9a3c14c329713f16d14147b81a4b8031028a4f82..778a56eb512edde3aac6c2a4d668cc73ab3d8460 100644 (file)
@@ -46,6 +46,8 @@ static const char *me;
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
+static char *get_encoding(const char *message);
+
 static void parse_args(int argc, const char **argv)
 {
        const char * const * usage_str =
@@ -85,33 +87,64 @@ static void parse_args(int argc, const char **argv)
                exit(1);
 }
 
-static char *get_oneline(const char *message)
+struct commit_message {
+       char *parent_label;
+       const char *label;
+       const char *subject;
+       char *reencoded_message;
+       const char *message;
+};
+
+static int get_message(const char *raw_message, struct commit_message *out)
 {
-       char *result;
-       const char *p = message, *abbrev, *eol;
+       const char *encoding;
+       const char *p, *abbrev, *eol;
+       char *q;
        int abbrev_len, oneline_len;
 
-       if (!p)
-               die ("Could not read commit message of %s",
-                               sha1_to_hex(commit->object.sha1));
+       if (!raw_message)
+               return -1;
+       encoding = get_encoding(raw_message);
+       if (!encoding)
+               encoding = "UTF-8";
+       if (!git_commit_encoding)
+               git_commit_encoding = "UTF-8";
+       if ((out->reencoded_message = reencode_string(raw_message,
+                                       git_commit_encoding, encoding)))
+               out->message = out->reencoded_message;
+
+       abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
+       abbrev_len = strlen(abbrev);
+
+       /* Find beginning and end of commit subject. */
+       p = out->message;
        while (*p && (*p != '\n' || p[1] != '\n'))
                p++;
-
        if (*p) {
                p += 2;
                for (eol = p + 1; *eol && *eol != '\n'; eol++)
                        ; /* do nothing */
        } else
                eol = p;
-       abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
-       abbrev_len = strlen(abbrev);
        oneline_len = eol - p;
-       result = xmalloc(abbrev_len + 5 + oneline_len);
-       memcpy(result, abbrev, abbrev_len);
-       memcpy(result + abbrev_len, "... ", 4);
-       memcpy(result + abbrev_len + 4, p, oneline_len);
-       result[abbrev_len + 4 + oneline_len] = '\0';
-       return result;
+
+       out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
+                             strlen("... ") + oneline_len + 1);
+       q = out->parent_label;
+       q = mempcpy(q, "parent of ", strlen("parent of "));
+       out->label = q;
+       q = mempcpy(q, abbrev, abbrev_len);
+       q = mempcpy(q, "... ", strlen("... "));
+       out->subject = q;
+       q = mempcpy(q, p, oneline_len);
+       *q = '\0';
+       return 0;
+}
+
+static void free_message(struct commit_message *msg)
+{
+       free(msg->parent_label);
+       free(msg->reencoded_message);
 }
 
 static char *get_encoding(const char *message)
@@ -271,9 +304,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
 {
        unsigned char head[20];
        struct commit *base, *next, *parent;
+       const char *base_label, *next_label;
        int i, index_fd, clean;
-       char *oneline, *reencoded_message = NULL;
-       const char *message, *encoding;
+       struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
        char *defmsg = NULL;
        struct merge_options o;
        struct tree *result, *next_tree, *base_tree, *head_tree;
@@ -349,14 +382,14 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        if (allow_ff && !hashcmp(parent->object.sha1, head))
                return fast_forward_to(commit->object.sha1, head);
 
-       if (!(message = commit->buffer))
-               die ("Cannot get commit message for %s",
-                               sha1_to_hex(commit->object.sha1));
-
        if (parent && parse_commit(parent) < 0)
                die("%s: cannot parse parent commit %s",
                    me, sha1_to_hex(parent->object.sha1));
 
+       if (get_message(commit->buffer, &msg) != 0)
+               die("Cannot get commit message for %s",
+                               sha1_to_hex(commit->object.sha1));
+
        /*
         * "commit" is an existing commit.  We would want to apply
         * the difference it introduces since its first parent "prev"
@@ -368,26 +401,15 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
                                           LOCK_DIE_ON_ERROR);
 
-       encoding = get_encoding(message);
-       if (!encoding)
-               encoding = "UTF-8";
-       if (!git_commit_encoding)
-               git_commit_encoding = "UTF-8";
-       if ((reencoded_message = reencode_string(message,
-                                       git_commit_encoding, encoding)))
-               message = reencoded_message;
-
-       oneline = get_oneline(message);
-
        index_fd = hold_locked_index(&index_lock, 1);
 
        if (action == REVERT) {
-               char *oneline_body = strchr(oneline, ' ');
-
                base = commit;
+               base_label = msg.label;
                next = parent;
+               next_label = msg.parent_label;
                add_to_msg("Revert \"");
-               add_to_msg(oneline_body + 1);
+               add_to_msg(msg.subject);
                add_to_msg("\"\n\nThis reverts commit ");
                add_to_msg(sha1_to_hex(commit->object.sha1));
 
@@ -398,9 +420,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
                add_to_msg(".\n");
        } else {
                base = parent;
+               base_label = msg.parent_label;
                next = commit;
-               set_author_ident_env(message);
-               add_message_to_msg(message);
+               next_label = msg.label;
+               set_author_ident_env(msg.message);
+               add_message_to_msg(msg.message);
                if (no_replay) {
                        add_to_msg("(cherry picked from commit ");
                        add_to_msg(sha1_to_hex(commit->object.sha1));
@@ -410,8 +434,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
 
        read_cache();
        init_merge_options(&o);
+       o.ancestor = base ? base_label : "(empty tree)";
        o.branch1 = "HEAD";
-       o.branch2 = oneline;
+       o.branch2 = next ? next_label : "(empty tree)";
 
        head_tree = parse_tree_indirect(head);
        next_tree = next ? next->tree : empty_tree();
@@ -475,7 +500,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
                args[i] = NULL;
                return execv_git_cmd(args);
        }
-       free(reencoded_message);
+       free_message(&msg);
        free(defmsg);
 
        return 0;
diff --git a/cache.h b/cache.h
index 6dcb100a6cfc1b1d311602507bc3dcb483c1558d..5eb0573bcc81050cc06a304f346fe5f41ebe242e 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -701,7 +701,7 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *
        return read_sha1_file_repl(sha1, type, size, NULL);
 }
 extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
+extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
 extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 
diff --git a/contrib/ciabot/README b/contrib/ciabot/README
new file mode 100644 (file)
index 0000000..3b916ac
--- /dev/null
@@ -0,0 +1,12 @@
+These are hook scripts for the CIA notification service at <http://cia.vc/>
+
+They are maintained by Eric S. Raymond <esr@thyrsus.com>.  There is an
+upstream resource page for them at <http://www.catb.org/esr/ciabot/>,
+but they are unlikely to change rapidly.
+
+You probably want the Python version; it's faster, more capable, and
+better documented.  The shell version is maintained only as a fallback
+for use on hosting sites that don't permit Python hook scripts.
+
+You will find installation instructions for each script in its comment
+header.
diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py
new file mode 100755 (executable)
index 0000000..d0627e0
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
+# Distributed under BSD terms.
+#
+# This script contains porcelain and porcelain byproducts.
+# It's Python because the Python standard libraries avoid portability/security
+# issues raised by callouts in the ancestral Perl and sh scripts.  It should
+# be compatible back to Python 2.1.5
+#
+# usage: ciabot.py [-V] [-n] [-p projectname]  [refname [commits...]]
+#
+# This script is meant to be run either in a post-commit hook or in an
+# update hook.  If there's nothing unusual about your hosting setup,
+# you can specify the project name with a -p option and avoid having
+# to modify this script.  Try it with -n to see the notification mail
+# dumped to stdout and verify that it looks sane. With -V it dumps its
+# version and exits.
+#
+# In post-commit, run it without arguments (other than possibly a -p
+# option). It will query for current HEAD and the latest commit ID to
+# get the information it needs.
+#
+# In update, call it with a refname followed by a list of commits:
+# You want to reverse the order git rev-list emits becxause it lists
+# from most recent to oldest.
+#
+# /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
+#
+# Note: this script uses mail, not XML-RPC, in order to avoid stalling
+# until timeout when the CIA XML-RPC server is down.
+#
+
+#
+# The project as known to CIA. You will either want to change this
+# or invoke the script with a -p option to set it.
+#
+project=None
+
+#
+# You may not need to change these:
+#
+import os, sys, commands, socket, urllib
+
+# Name of the repository.
+# You can hardwire this to make the script faster.
+repo = os.path.basename(os.getcwd())
+
+# Fully-qualified domain name of this host.
+# You can hardwire this to make the script faster.
+host = socket.getfqdn()
+
+# Changeset URL prefix for your repo: when the commit ID is appended
+# to this, it should point at a CGI that will display the commit
+# through gitweb or something similar. The defaults will probably
+# work if you have a typical gitweb/cgit setup.
+#
+#urlprefix="http://%(host)s/cgi-bin/gitweb.cgi?p=%(repo)s;a=commit;h="
+urlprefix="http://%(host)s/cgi-bin/cgit.cgi/%(repo)s/commit/?id="
+
+# The service used to turn your gitwebbish URL into a tinyurl so it
+# will take up less space on the IRC notification line.
+tinyifier = "http://tinyurl.com/api-create.php?url="
+
+# The template used to generate the XML messages to CIA.  You can make
+# visible changes to the IRC-bot notification lines by hacking this.
+# The default will produce a notfication line that looks like this:
+#
+# ${project}: ${author} ${repo}:${branch} * ${rev} ${files}: ${logmsg} ${url}
+#
+# By omitting $files you can collapse the files part to a single slash.
+xml = '''\
+<message>
+  <generator>
+    <name>CIA Python client for Git</name>
+    <version>%(gitver)s</version>
+    <url>%(generator)s</url>
+  </generator>
+  <source>
+    <project>%(project)s</project>
+    <branch>%(repo)s:%(branch)s</branch>
+  </source>
+  <timestamp>%(ts)s</timestamp>
+  <body>
+    <commit>
+      <author>%(author)s</author>
+      <revision>%(rev)s</revision>
+      <files>
+        %(files)s
+      </files>
+      <log>%(logmsg)s %(url)s</log>
+      <url>%(url)s</url>
+    </commit>
+  </body>
+</message>
+'''
+
+#
+# No user-serviceable parts below this line:
+#
+
+# Addresses for the e-mail. The from address is a dummy, since CIA
+# will never reply to this mail.
+fromaddr = "CIABOT-NOREPLY@" + host
+toaddr = "cia@cia.navi.cx"
+
+# Identify the generator script.
+# Should only change when the script itself gets a new home and maintainer.
+generator="http://www.catb.org/~esr/ciabot.py"
+
+def do(command):
+    return commands.getstatusoutput(command)[1]
+
+def report(refname, merged):
+    "Generate a commit notification to be reported to CIA"
+
+    # Try to tinyfy a reference to a web view for this commit.
+    try:
+        url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
+    except:
+        url = urlprefix + merged
+
+    branch = os.path.basename(refname)
+
+    # Compute a shortnane for the revision
+    rev = do("git describe ${merged} 2>/dev/null") or merged[:12]
+
+    # Extract the neta-information for the commit
+    rawcommit = do("git cat-file commit " + merged)
+    files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")
+    inheader = True
+    headers = {}
+    logmsg = ""
+    for line in rawcommit.split("\n"):
+        if inheader:
+            if line:
+                fields = line.split()
+                headers[fields[0]] = " ".join(fields[1:])
+            else:
+                inheader = False
+        else:
+            logmsg = line
+            break
+    (author, ts) = headers["author"].split(">")
+
+    # This discards the part of the authors addrsss after @.
+    # Might be bnicece to ship the full email address, if not
+    # for spammers' address harvesters - getting this wrong
+    # would make the freenode #commits channel into harvester heaven.
+    author = author.replace("<", "").split("@")[0].split()[-1]
+
+    # This ignores the timezone.  Not clear what to do with it...
+    ts = ts.strip().split()[0]
+
+    context = locals()
+    context.update(globals())
+
+    out = xml % context
+
+    message = '''\
+Message-ID: <%(merged)s.%(author)s@%(project)s>
+From: %(fromaddr)s
+To: %(toaddr)s
+Content-type: text/xml
+Subject: DeliverXML
+
+%(out)s''' % locals()
+
+    return message
+
+if __name__ == "__main__":
+    import getopt
+
+    try:
+        (options, arguments) = getopt.getopt(sys.argv[1:], "np:V")
+    except getopt.GetoptError, msg:
+        print "ciabot.py: " + str(msg)
+        raise SystemExit, 1
+
+    mailit = True
+    for (switch, val) in options:
+        if switch == '-p':
+            project = val
+        elif switch == '-n':
+            mailit = False
+        elif switch == '-V':
+            print "ciabot.py: version 3.2"
+            sys.exit(0)
+
+    # Cough and die if user has not specified a project
+    if not project:
+        sys.stderr.write("ciabot.py: no project specified, bailing out.\n")
+        sys.exit(1)
+
+    # We'll need the git version number.
+    gitver = do("git --version").split()[0]
+
+    urlprefix = urlprefix % globals()
+
+    # The script wants a reference to head followed by the list of
+    # commit ID to report about.
+    if len(arguments) == 0:
+        refname = do("git symbolic-ref HEAD 2>/dev/null")
+        merges = [do("git rev-parse HEAD")]
+    else:
+        refname = arguments[0]
+        merges = arguments[1:]
+
+    if mailit:
+        import smtplib
+        server = smtplib.SMTP('localhost')
+
+    for merged in merges:
+        message = report(refname, merged)
+        if mailit:
+            server.sendmail(fromaddr, [toaddr], message)
+        else:
+            print message
+
+    if mailit:
+        server.quit()
+
+#End
diff --git a/contrib/ciabot/ciabot.sh b/contrib/ciabot/ciabot.sh
new file mode 100755 (executable)
index 0000000..eb87bba
--- /dev/null
@@ -0,0 +1,192 @@
+#!/bin/sh
+# Distributed under the terms of the GNU General Public License v2
+# Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org>
+# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
+# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
+#
+# This is a version 3.x of ciabot.sh; use -V to find the exact
+# version.  Versions 1 and 2 were shipped in 2006 and 2008 and are not
+# version-stamped.  The version 2 maintainer has passed the baton.
+#
+# Note: This script should be considered obsolete.
+# There is a faster, better-documented rewrite in Python: find it as ciabot.py
+# Use this only if your hosting site forbids Python hooks.
+#
+# Originally based on Git ciabot.pl by Petr Baudis.
+# This script contains porcelain and porcelain byproducts.
+#
+# usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit]
+#
+# This script is meant to be run either in a post-commit hook or in an
+# update hook.  If there's nothing unusual about your hosting setup,
+# you can specify the project name with a -p option and avoid having
+# to modify this script.  Try it with -n first to see the notification
+# mail dumped to stdout and verify that it looks sane.  Use -V to dump
+# the version and exit.
+#
+# In post-commit, run it without arguments (other than possibly a -p
+# option). It will query for current HEAD and the latest commit ID to
+# get the information it needs.
+#
+# In update, you have to call it once per merged commit:
+#
+#       refname=$1
+#       oldhead=$2
+#       newhead=$3
+#       for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
+#               /path/to/ciabot.bash ${refname} ${merged}
+#       done
+#
+# The reason for the tac call ids that git rev-list emits commits from
+# most recent to least - better to ship notifactions from oldest to newest.
+#
+# Note: this script uses mail, not XML-RPC, in order to avoid stalling
+# until timeout when the CIA XML-RPC server is down.
+#
+
+#
+# The project as known to CIA. You will either want to change this
+# or set the project name with a -p option.
+#
+project=
+
+#
+# You may not need to change these:
+#
+
+# Name of the repository.
+# You can hardwire this to make the script faster.
+repo="`basename ${PWD}`"
+
+# Fully qualified domain name of the repo host.
+# You can hardwire this to make the script faster.
+host=`hostname --fqdn`
+
+# Changeset URL prefix for your repo: when the commit ID is appended
+# to this, it should point at a CGI that will display the commit
+# through gitweb or something similar. The defaults will probably
+# work if you have a typical gitweb/cgit setup.
+#urlprefix="http://${host}/cgi-bin/gitweb.cgi?p=${repo};a=commit;h="
+urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id="
+
+#
+# You probably will not need to change the following:
+#
+
+# Identify the script. Should change only when the script itself
+# gets a new home and maintainer.
+generator="http://www.catb.org/~esr/ciabot/ciabot.sh"
+
+# Addresses for the e-mail
+from="CIABOT-NOREPLY@${host}"
+to="cia@cia.navi.cx"
+
+# SMTP client to use - may need to edit the absolute pathname for your system
+sendmail="sendmail -t -f ${from}"
+
+#
+# No user-serviceable parts below this line:
+#
+
+# Should include all places sendmail is likely to lurk.
+PATH="$PATH:/usr/sbin/"
+
+mode=mailit
+while getopts pnV opt
+do
+    case $opt in
+       p) project=$2; shift ; shift ;;
+       n) mode=dumpit; shift ;;
+       V) echo "ciabot.sh: version 3.2"; exit 0; shift ;;
+    esac
+done
+
+# Cough and die if user has not specified a project
+if [ -z "$project" ]
+then
+    echo "ciabot.sh: no project specified, bailing out." >&2
+    exit 1
+fi
+
+if [ $# -eq 0 ] ; then
+       refname=$(git symbolic-ref HEAD 2>/dev/null)
+       merged=$(git rev-parse HEAD)
+else
+       refname=$1
+       merged=$2
+fi
+
+# This tries to turn your gitwebbish URL into a tinyurl so it will take up
+# less space on the IRC notification line. Some repo sites (I'm looking at
+# you, berlios.de!) forbid wget calls for security reasons.  On these,
+# the code will fall back to the full un-tinyfied URL.
+longurl=${urlprefix}${merged}
+url=$(wget -O - -q http://tinyurl.com/api-create.php?url=${longurl} 2>/dev/null)
+if [ -z "$url" ]; then
+       url="${longurl}"
+fi
+
+refname=${refname##refs/heads/}
+
+gitver=$(git --version)
+gitver=${gitver##* }
+
+rev=$(git describe ${merged} 2>/dev/null)
+# ${merged:0:12} was the only bashism left in the 2008 version of this
+# script, according to checkbashisms.  Replace it with ${merged} here
+# because it was just a fallback anyway, and it's worth accepting a
+# longer fallback for faster execution and removing the bash
+# dependency.
+[ -z ${rev} ] && rev=${merged}
+
+# This discards the part of the author's address after @.
+# Might be nice to ship the full email address, if not
+# for spammers' address harvesters - getting this wrong
+# would make the freenode #commits channel into harvester heaven.
+rawcommit=$(git cat-file commit ${merged})
+author=$(echo "$rawcommit" | sed -n -e '/^author .*<\([^@]*\).*$/s--\1-p')
+logmessage=$(echo "$rawcommit" | sed -e '1,/^$/d' | head -n 1)
+logmessage=$(echo "$logmessage" | sed 's/\&/&amp\;/g; s/</&lt\;/g; s/>/&gt\;/g')
+ts=$(echo "$rawcommit" | sed -n -e '/^author .*> \([0-9]\+\).*$/s--\1-p')
+files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-')
+
+out="
+<message>
+  <generator>
+    <name>CIA Shell client for Git</name>
+    <version>${gitver}</version>
+    <url>${generator}</url>
+  </generator>
+  <source>
+    <project>${project}</project>
+    <branch>$repo:${refname}</branch>
+  </source>
+  <timestamp>${ts}</timestamp>
+  <body>
+    <commit>
+      <author>${author}</author>
+      <revision>${rev}</revision>
+      <files>
+       ${files}
+      </files>
+      <log>${logmessage} ${url}</log>
+      <url>${url}</url>
+    </commit>
+  </body>
+</message>"
+
+if [ "$mode" = "dumpit" ]
+then
+    sendmail=cat
+fi
+
+${sendmail} << EOM
+Message-ID: <${merged}.${author}@${project}>
+From: ${from}
+To: ${to}
+Content-type: text/xml
+Subject: DeliverXML
+${out}
+EOM
+
+# vim: set tw=70 :
index 733ac39a32f6fd0b4f1546d429ac55c4ad6699b6..545bd4b38368e3c2a3958133bbeef6a19e831fff 100755 (executable)
@@ -627,10 +627,19 @@ __git_aliased_command ()
        local word cmdline=$(git --git-dir="$(__gitdir)" \
                config --get "alias.$1")
        for word in $cmdline; do
-               if [ "${word##-*}" ]; then
-                       echo $word
+               case "$word" in
+               \!gitk|gitk)
+                       echo "gitk"
                        return
-               fi
+                       ;;
+               \!*)    : shell command alias ;;
+               -*)     : option ;;
+               *=*)    : setting env ;;
+               git)    : git itself ;;
+               *)
+                       echo "$word"
+                       return
+               esac
        done
 }
 
@@ -1084,6 +1093,11 @@ _git_gc ()
        COMPREPLY=()
 }
 
+_git_gitk ()
+{
+       _gitk
+}
+
 _git_grep ()
 {
        __git_has_doubledash && return
@@ -1436,6 +1450,11 @@ _git_send_email ()
        COMPREPLY=()
 }
 
+_git_stage ()
+{
+       _git_add
+}
+
 __git_config_get_set_variables ()
 {
        local prevword word config_file= c=$COMP_CWORD
@@ -2167,6 +2186,11 @@ _git_tag ()
        esac
 }
 
+_git_whatchanged ()
+{
+       _git_log
+}
+
 _git ()
 {
        local i c=1 command __git_dir
@@ -2203,64 +2227,14 @@ _git ()
                return
        fi
 
+       local completion_func="_git_${command//-/_}"
+       declare -F $completion_func >/dev/null && $completion_func && return
+
        local expansion=$(__git_aliased_command "$command")
-       [ "$expansion" ] && command="$expansion"
-
-       case "$command" in
-       am)          _git_am ;;
-       add)         _git_add ;;
-       apply)       _git_apply ;;
-       archive)     _git_archive ;;
-       bisect)      _git_bisect ;;
-       bundle)      _git_bundle ;;
-       branch)      _git_branch ;;
-       checkout)    _git_checkout ;;
-       cherry)      _git_cherry ;;
-       cherry-pick) _git_cherry_pick ;;
-       clean)       _git_clean ;;
-       clone)       _git_clone ;;
-       commit)      _git_commit ;;
-       config)      _git_config ;;
-       describe)    _git_describe ;;
-       diff)        _git_diff ;;
-       difftool)    _git_difftool ;;
-       fetch)       _git_fetch ;;
-       format-patch) _git_format_patch ;;
-       fsck)        _git_fsck ;;
-       gc)          _git_gc ;;
-       grep)        _git_grep ;;
-       help)        _git_help ;;
-       init)        _git_init ;;
-       log)         _git_log ;;
-       ls-files)    _git_ls_files ;;
-       ls-remote)   _git_ls_remote ;;
-       ls-tree)     _git_ls_tree ;;
-       merge)       _git_merge;;
-       mergetool)   _git_mergetool;;
-       merge-base)  _git_merge_base ;;
-       mv)          _git_mv ;;
-       name-rev)    _git_name_rev ;;
-       notes)       _git_notes ;;
-       pull)        _git_pull ;;
-       push)        _git_push ;;
-       rebase)      _git_rebase ;;
-       remote)      _git_remote ;;
-       replace)     _git_replace ;;
-       reset)       _git_reset ;;
-       revert)      _git_revert ;;
-       rm)          _git_rm ;;
-       send-email)  _git_send_email ;;
-       shortlog)    _git_shortlog ;;
-       show)        _git_show ;;
-       show-branch) _git_show_branch ;;
-       stash)       _git_stash ;;
-       stage)       _git_add ;;
-       submodule)   _git_submodule ;;
-       svn)         _git_svn ;;
-       tag)         _git_tag ;;
-       whatchanged) _git_log ;;
-       *)           COMPREPLY=() ;;
-       esac
+       if [ -n "$expansion" ]; then
+               completion_func="_git_${expansion//-/_}"
+               declare -F $completion_func >/dev/null && $completion_func
+       fi
 }
 
 _gitk ()
index 7051a83a59758277dd60fe026dea730eb7b6b115..82f5ed3ddc8adb1b9b281c3912f4e67c53ef152f 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 ## zip archive frontend for git-fast-import
 ##
index 854cd94ba55e498a3ff6c26be3dbe5191faa19dc..046cb2b268a82358630e86bb55cf8b4e58c730fb 100755 (executable)
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#!/usr/bin/env python
 
 """ hg-to-git.py - A Mercurial to GIT converter
 
index 0f3d97b67eef3108728265e26f5d79c4526d11ac..b6e534b65b687d955a878d902b9bb46cfa2e42ce 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #
 # This tool is copyright (c) 2006, Sean Estabrooks.
 # It is released under the Gnu Public License, version 2.
index 7d9e1c03e88d7785f4ff0d534563ba5778fbc244..a90ab10505a3694de83a0ffd8fc472518f12cf2b 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -590,14 +590,17 @@ static int execute(struct sockaddr *addr)
 static int addrcmp(const struct sockaddr_storage *s1,
     const struct sockaddr_storage *s2)
 {
-       if (s1->ss_family != s2->ss_family)
-               return s1->ss_family - s2->ss_family;
-       if (s1->ss_family == AF_INET)
+       const struct sockaddr *sa1 = (const struct sockaddr*) s1;
+       const struct sockaddr *sa2 = (const struct sockaddr*) s2;
+
+       if (sa1->sa_family != sa2->sa_family)
+               return sa1->sa_family - sa2->sa_family;
+       if (sa1->sa_family == AF_INET)
                return memcmp(&((struct sockaddr_in *)s1)->sin_addr,
                    &((struct sockaddr_in *)s2)->sin_addr,
                    sizeof(struct in_addr));
 #ifndef NO_IPV6
-       if (s1->ss_family == AF_INET6)
+       if (sa1->sa_family == AF_INET6)
                return memcmp(&((struct sockaddr_in6 *)s1)->sin6_addr,
                    &((struct sockaddr_in6 *)s2)->sin6_addr,
                    sizeof(struct in6_addr));
diff --git a/diff.c b/diff.c
index 2daa732a360b2e846791156be5ceb33b85b4eac9..a1bf1e9cb37104cda8168c5118769ce5bbcfcbb2 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -14,6 +14,7 @@
 #include "userdiff.h"
 #include "sigchain.h"
 #include "submodule.h"
+#include "ll-merge.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -550,6 +551,10 @@ static void emit_rewrite_diff(const char *name_a,
                emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
        if (lc_b)
                emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
+       if (textconv_one)
+               free((char *)data_one);
+       if (textconv_two)
+               free((char *)data_two);
 }
 
 struct diff_words_buffer {
@@ -1370,37 +1375,32 @@ static void free_diffstat_info(struct diffstat_t *diffstat)
 struct checkdiff_t {
        const char *filename;
        int lineno;
+       int conflict_marker_size;
        struct diff_options *o;
        unsigned ws_rule;
        unsigned status;
 };
 
-static int is_conflict_marker(const char *line, unsigned long len)
+static int is_conflict_marker(const char *line, int marker_size, unsigned long len)
 {
        char firstchar;
        int cnt;
 
-       if (len < 8)
+       if (len < marker_size + 1)
                return 0;
        firstchar = line[0];
        switch (firstchar) {
-       case '=': case '>': case '<':
+       case '=': case '>': case '<': case '|':
                break;
        default:
                return 0;
        }
-       for (cnt = 1; cnt < 7; cnt++)
+       for (cnt = 1; cnt < marker_size; cnt++)
                if (line[cnt] != firstchar)
                        return 0;
-       /* line[0] thru line[6] are same as firstchar */
-       if (firstchar == '=') {
-               /* divider between ours and theirs? */
-               if (len != 8 || line[7] != '\n')
-                       return 0;
-       } else if (len < 8 || !isspace(line[7])) {
-               /* not divider before ours nor after theirs */
+       /* line[1] thru line[marker_size-1] are same as firstchar */
+       if (len < marker_size + 1 || !isspace(line[marker_size]))
                return 0;
-       }
        return 1;
 }
 
@@ -1408,6 +1408,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
 {
        struct checkdiff_t *data = priv;
        int color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF);
+       int marker_size = data->conflict_marker_size;
        const char *ws = diff_get_color(color_diff, DIFF_WHITESPACE);
        const char *reset = diff_get_color(color_diff, DIFF_RESET);
        const char *set = diff_get_color(color_diff, DIFF_FILE_NEW);
@@ -1416,7 +1417,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
        if (line[0] == '+') {
                unsigned bad;
                data->lineno++;
-               if (is_conflict_marker(line + 1, len - 1)) {
+               if (is_conflict_marker(line + 1, marker_size, len - 1)) {
                        data->status |= 1;
                        fprintf(data->o->file,
                                "%s:%d: leftover conflict marker\n",
@@ -1860,6 +1861,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        data.lineno = 0;
        data.o = o;
        data.ws_rule = whitespace_rule(attr_path);
+       data.conflict_marker_size = ll_merge_marker_size(attr_path);
 
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
index a3c45373669cd8482c04d5815862ed36a153572d..7e62b552700a580646dbb6a8921c40761d6b57a2 100644 (file)
@@ -55,7 +55,8 @@
 # else
 # define _XOPEN_SOURCE 500
 # endif
-#elif !defined(__APPLE__) && !defined(__FreeBSD__)  && !defined(__USLC__) && !defined(_M_UNIX) && !defined(sgi)
+#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
+      !defined(_M_UNIX) && !defined(sgi) && !defined(__DragonFly__)
 #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #endif
@@ -331,6 +332,7 @@ extern int git_vsnprintf(char *str, size_t maxsize,
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
 #define HAVE_STRCHRNUL
+#define HAVE_MEMPCPY
 #endif
 #endif
 
@@ -344,6 +346,14 @@ static inline char *gitstrchrnul(const char *s, int c)
 }
 #endif
 
+#ifndef HAVE_MEMPCPY
+#define mempcpy gitmempcpy
+static inline void *gitmempcpy(void *dest, const void *src, size_t n)
+{
+       return (char *)memcpy(dest, src, n) + n;
+}
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 extern char *xstrdup(const char *str);
index 1d116bfae2175891905d40ba4b55b331fba63372..b817c4a76e54c31f5a21d8196729f0cfb31997cf 100755 (executable)
@@ -20,6 +20,7 @@ v,verbose          display a diffstat of what changed upstream
 onto=              rebase onto given branch instead of upstream
 p,preserve-merges  try to recreate merges instead of ignoring them
 s,strategy=        use the given merge strategy
+no-ff              cherry-pick all commits, even if unchanged
 m,merge            always used (no-op)
 i,interactive      always used (no-op)
  Actions:
@@ -110,6 +111,7 @@ VERBOSE=
 OK_TO_SKIP_PRE_REBASE=
 REBASE_ROOT=
 AUTOSQUASH=
+NEVER_FF=
 
 GIT_CHERRY_PICK_HELP="  After resolving the conflicts,
 mark the corrected paths with 'git add <paths>', and
@@ -232,6 +234,7 @@ do_with_author () {
 pick_one () {
        ff=--ff
        case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
+       case "$NEVER_FF" in '') ;; ?*) ff= ;; esac
        output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
        test -d "$REWRITTEN" &&
                pick_one_preserving_merges "$@" && return
@@ -782,6 +785,9 @@ first and then run 'git rebase --continue' again."
        -i)
                # yeah, we know
                ;;
+       --no-ff)
+               NEVER_FF=t
+               ;;
        --root)
                REBASE_ROOT=t
                ;;
@@ -823,8 +829,6 @@ first and then run 'git rebase --continue' again."
 
                if test ! -z "$1"
                then
-                       output git show-ref --verify --quiet "refs/heads/$1" ||
-                               die "Invalid branchname: $1"
                        output git checkout "$1" ||
                                die "Could not checkout $1"
                fi
@@ -967,7 +971,7 @@ EOF
                has_action "$TODO" ||
                        die_abort "Nothing to do"
 
-               test -d "$REWRITTEN" || skip_unnecessary_picks
+               test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks
 
                git update-ref ORIG_HEAD $HEAD
                output git checkout $ONTO && do_rest
index e0eb9568f3d12a068d46196d2dc896dde4d35fd3..44f5c65fdb5e81c4b660a666c2edd71aa75c5c1a 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
+USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
 LONG_USAGE='git-rebase replaces <branch> with a new branch of the
 same name.  When the --onto option is provided the new branch starts
 out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -353,7 +353,7 @@ do
        --root)
                rebase_root=t
                ;;
-       -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase)
+       -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff)
                force_rebase=t
                ;;
        --rerere-autoupdate|--no-rerere-autoupdate)
index d612ae8729e0a15f501214b6f27f4fc32a66e9fd..ce569a9c8f964b3cdc8920325bc817141035c2c3 100755 (executable)
@@ -64,6 +64,8 @@ sub usage {
     --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
     --smtp-encryption       <str>  * tls or ssl; anything else disables.
     --smtp-ssl                     * Deprecated. Use '--smtp-encryption ssl'.
+    --smtp-domain           <str>  * The domain name sent to HELO/EHLO handshake
+    --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.
 
   Automating:
     --identity              <str>  * Use the sendemail.<id> options.
@@ -130,6 +132,8 @@ sub format_2822_time {
 my $have_mail_address = eval { require Mail::Address; 1 };
 my $smtp;
 my $auth;
+my $mail_domain_default = "localhost.localdomain";
+my $mail_domain;
 
 sub unique_email_list(@);
 sub cleanup_compose_files();
@@ -162,9 +166,12 @@ sub format_2822_time {
 
 # Handle interactive edition of files.
 my $multiedit;
-my $editor = Git::command_oneline('var', 'GIT_EDITOR');
+my $editor;
 
 sub do_edit {
+       if (!defined($editor)) {
+               $editor = Git::command_oneline('var', 'GIT_EDITOR');
+       }
        if (defined($multiedit) && !$multiedit) {
                map {
                        system('sh', '-c', $editor.' "$@"', $editor, $_);
@@ -187,6 +194,8 @@ sub do_edit {
 my ($validate, $confirm);
 my (@suppress_cc);
 
+my ($debug_net_smtp) = 0;              # Net::SMTP, see send_message()
+
 my $not_set_by_user = "true but not set by the user";
 
 my %config_bool_settings = (
@@ -273,6 +282,8 @@ sub signal_handler {
                    "smtp-pass:s" => \$smtp_authpass,
                    "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
                    "smtp-encryption=s" => \$smtp_encryption,
+                   "smtp-debug:i" => \$debug_net_smtp,
+                   "smtp-domain:s" => \$mail_domain,
                    "identity=s" => \$identity,
                    "annotate" => \$annotate,
                    "compose" => \$compose,
@@ -836,6 +847,62 @@ sub sanitize_address
 
 }
 
+# Returns the local Fully Qualified Domain Name (FQDN) if available.
+#
+# Tightly configured MTAa require that a caller sends a real DNS
+# domain name that corresponds the IP address in the HELO/EHLO
+# handshake. This is used to verify the connection and prevent
+# spammers from trying to hide their identity. If the DNS and IP don't
+# match, the receiveing MTA may deny the connection.
+#
+# Here is a deny example of Net::SMTP with the default "localhost.localdomain"
+#
+# Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
+# Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
+#
+# This maildomain*() code is based on ideas in Perl library Test::Reporter
+# /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
+
+sub maildomain_net
+{
+       my $maildomain;
+
+       if (eval { require Net::Domain; 1 }) {
+               my $domain = Net::Domain::domainname();
+               $maildomain = $domain
+                       unless $^O eq 'darwin' && $domain =~ /\.local$/;
+       }
+
+       return $maildomain;
+}
+
+sub maildomain_mta
+{
+       my $maildomain;
+
+       if (eval { require Net::SMTP; 1 }) {
+               for my $host (qw(mailhost localhost)) {
+                       my $smtp = Net::SMTP->new($host);
+                       if (defined $smtp) {
+                               my $domain = $smtp->domain;
+                               $smtp->quit;
+
+                               $maildomain = $domain
+                                       unless $^O eq 'darwin' && $domain =~ /\.local$/;
+
+                               last if $maildomain;
+                       }
+               }
+       }
+
+       return $maildomain;
+}
+
+sub maildomain
+{
+       return maildomain_net() || maildomain_mta() || $mail_domain_default;
+}
+
 # Returns 1 if the message was sent, and 0 otherwise.
 # In actuality, the whole program dies when there
 # is an error sending a message.
@@ -938,13 +1005,19 @@ sub send_message
                if ($smtp_encryption eq 'ssl') {
                        $smtp_server_port ||= 465; # ssmtp
                        require Net::SMTP::SSL;
-                       $smtp ||= Net::SMTP::SSL->new($smtp_server, Port => $smtp_server_port);
+                       $mail_domain ||= maildomain();
+                       $smtp ||= Net::SMTP::SSL->new($smtp_server,
+                                                     Hello => $mail_domain,
+                                                     Port => $smtp_server_port);
                }
                else {
                        require Net::SMTP;
+                       $mail_domain ||= maildomain();
                        $smtp ||= Net::SMTP->new((defined $smtp_server_port)
                                                 ? "$smtp_server:$smtp_server_port"
-                                                : $smtp_server);
+                                                : $smtp_server,
+                                                Hello => $mail_domain,
+                                                Debug => $debug_net_smtp);
                        if ($smtp_encryption eq 'tls' && $smtp) {
                                require Net::SMTP::SSL;
                                $smtp->command('STARTTLS');
@@ -963,7 +1036,11 @@ sub send_message
                }
 
                if (!$smtp) {
-                       die "Unable to initialize SMTP properly.  Is there something wrong with your config?";
+                       die "Unable to initialize SMTP properly. Check config and use --smtp-debug. ",
+                           "VALUES: server=$smtp_server ",
+                           "encryption=$smtp_encryption ",
+                           "maildomain=$mail_domain",
+                           defined $smtp_server_port ? "port=$smtp_server_port" : "";
                }
 
                if (defined $smtp_authuser) {
index aa47e541ee4fe55254edc3fb59ef534ba4d5be66..59db3dc38e72fda88d521171a174c08b919677a9 100755 (executable)
@@ -210,14 +210,18 @@ list_stash () {
 }
 
 show_stash () {
+       have_stash || die 'No stash found'
+
        flags=$(git rev-parse --no-revs --flags "$@")
        if test -z "$flags"
        then
                flags=--stat
        fi
 
-       w_commit=$(git rev-parse --verify --default $ref_stash "$@") &&
-       b_commit=$(git rev-parse --verify "$w_commit^") &&
+       w_commit=$(git rev-parse --quiet --verify --default $ref_stash "$@") &&
+       b_commit=$(git rev-parse --quiet --verify "$w_commit^") ||
+               die "'$*' is not a stash"
+
        git diff $flags $b_commit $w_commit
 }
 
index ee74a5eed7758f1267441d85619969a121fb3cec..9533147ff2e06282dc8d60aeb371afa715e22cc1 100644 (file)
@@ -127,6 +127,9 @@ find $RPM_BUILD_ROOT -type f -name perllocal.pod -exec rm -f {} ';'
 rm -rf $RPM_BUILD_ROOT%{_mandir}
 %endif
 
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
+install -m 644 -T contrib/completion/git-completion.bash $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/git
+
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -136,6 +139,7 @@ rm -rf $RPM_BUILD_ROOT
 %doc README COPYING Documentation/*.txt
 %{!?_without_docs: %doc Documentation/*.html Documentation/howto}
 %{!?_without_docs: %doc Documentation/technical}
+%{_sysconfdir}/bash_completion.d
 
 %files svn
 %defattr(-,root,root)
@@ -192,6 +196,9 @@ rm -rf $RPM_BUILD_ROOT
 # No files for you!
 
 %changelog
+* Fri Mar 26 2010 Ian Ward Comfort <icomfort@stanford.edu>
+- Ship bash completion support from contrib/ in the core package.
+
 * Sun Jan 31 2010 Junio C Hamano <gitster@pobox.com>
 - Do not use %define inside %{!?...} construct.
 
index c62dfd0f4ddafbc82be15519f17815bbfcd62e8b..74b05dc91e42414147d5f3dc7b4fc66fb86c0eca 100644 (file)
@@ -7,7 +7,11 @@ pysetupfile:=setup.py
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 
 ifndef PYTHON_PATH
-       PYTHON_PATH = /usr/bin/python
+       ifeq ($(uname_S),FreeBSD)
+               PYTHON_PATH = /usr/local/bin/python
+       else
+               PYTHON_PATH = /usr/bin/python
+       endif
 endif
 ifndef prefix
        prefix = $(HOME)
diff --git a/grep.c b/grep.c
index fdc42062687fa6b8bb77c8d09ed58aee9107692d..543b1d53784c16020dea089f23c431c7f2608425 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -570,8 +570,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
                        if (opt->show_hunk_mark) {
                                output_color(opt, "--", 2, opt->color_sep);
                                opt->output(opt, "\n", 1);
-                       } else
-                               opt->show_hunk_mark = 1;
+                       }
                } else if (lno > opt->last_shown + 1) {
                        output_color(opt, "--", 2, opt->color_sep);
                        opt->output(opt, "\n", 1);
@@ -772,14 +771,6 @@ int grep_threads_ok(const struct grep_opt *opt)
            !opt->name_only)
                return 0;
 
-       /* If we are showing hunk marks, we should not do it for the
-        * first match. The synchronization problem we get for this
-        * constraint is not yet solved, so we disable threading in
-        * this case.
-        */
-       if (opt->pre_context || opt->post_context)
-               return 0;
-
        return 1;
 }
 
@@ -801,11 +792,14 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
        enum grep_context ctx = GREP_CONTEXT_HEAD;
        xdemitconf_t xecfg;
 
-       opt->last_shown = 0;
-
        if (!opt->output)
                opt->output = std_output;
 
+       if (opt->last_shown && (opt->pre_context || opt->post_context) &&
+           opt->output == std_output)
+               opt->show_hunk_mark = 1;
+       opt->last_shown = 0;
+
        if (buffer_is_binary(buf, size)) {
                switch (opt->binary) {
                case GREP_BINARY_DEFAULT:
index 345c12b79064f23e0ae0a15781731b9a42272d83..d1e83d0906dbc9d677630cdf74615ec3f9dfc46d 100644 (file)
@@ -538,15 +538,19 @@ static void service_rpc(char *service_name)
 
 static NORETURN void die_webcgi(const char *err, va_list params)
 {
-       char buffer[1000];
+       static int dead;
 
-       http_status(500, "Internal Server Error");
-       hdr_nocache();
-       end_headers();
+       if (!dead) {
+               char buffer[1000];
+               dead = 1;
 
-       vsnprintf(buffer, sizeof(buffer), err, params);
-       fprintf(stderr, "fatal: %s\n", buffer);
-       exit(0);
+               vsnprintf(buffer, sizeof(buffer), err, params);
+               fprintf(stderr, "fatal: %s\n", buffer);
+               http_status(500, "Internal Server Error");
+               hdr_nocache();
+               end_headers();
+       }
+       exit(0); /* we successfully reported a failure ;-) */
 }
 
 static char* getdir(void)
index 7107923a39247b5c18ad443dc2309971e44abdb4..9d0097ca02960460ff3a104f1739982fee453987 100644 (file)
@@ -1431,8 +1431,14 @@ static int count_messages(struct msg_data *msg)
 
        while (1) {
                if (!prefixcmp(p, "From ")) {
+                       p = strstr(p+5, "\nFrom: ");
+                       if (!p) break;
+                       p = strstr(p+7, "\nDate: ");
+                       if (!p) break;
+                       p = strstr(p+7, "\nSubject: ");
+                       if (!p) break;
+                       p += 10;
                        count++;
-                       p += 5;
                }
                p = strstr(p+5, "\nFrom ");
                if (!p)
index 82c7742e41f4645e7d6086bb277437a84ff4f03b..f9b3d854a921ab6fa3eed6f4dbf01af1a8657602 100644 (file)
@@ -15,7 +15,7 @@ struct ll_merge_driver;
 typedef int (*ll_merge_fn)(const struct ll_merge_driver *,
                           mmbuffer_t *result,
                           const char *path,
-                          mmfile_t *orig,
+                          mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
                           int flag,
@@ -36,7 +36,7 @@ struct ll_merge_driver {
 static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
                           mmbuffer_t *result,
                           const char *path_unused,
-                          mmfile_t *orig,
+                          mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
                           int flag, int marker_size)
@@ -57,7 +57,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
 static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        mmbuffer_t *result,
                        const char *path,
-                       mmfile_t *orig,
+                       mmfile_t *orig, const char *orig_name,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
                        int flag, int marker_size)
@@ -71,7 +71,8 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        path, name1, name2);
                return ll_binary_merge(drv_unused, result,
                                       path,
-                                      orig, src1, name1,
+                                      orig, orig_name,
+                                      src1, name1,
                                       src2, name2,
                                       flag, marker_size);
        }
@@ -83,13 +84,16 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                xmp.style = git_xmerge_style;
        if (marker_size > 0)
                xmp.marker_size = marker_size;
-       return xdl_merge(orig, src1, name1, src2, name2, &xmp, result);
+       xmp.ancestor = orig_name;
+       xmp.file1 = name1;
+       xmp.file2 = name2;
+       return xdl_merge(orig, src1, src2, &xmp, result);
 }
 
 static int ll_union_merge(const struct ll_merge_driver *drv_unused,
                          mmbuffer_t *result,
                          const char *path_unused,
-                         mmfile_t *orig,
+                         mmfile_t *orig, const char *orig_name,
                          mmfile_t *src1, const char *name1,
                          mmfile_t *src2, const char *name2,
                          int flag, int marker_size)
@@ -97,7 +101,7 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,
        /* Use union favor */
        flag = (flag & 1) | (XDL_MERGE_FAVOR_UNION << 1);
        return ll_xdl_merge(drv_unused, result, path_unused,
-                           orig, src1, NULL, src2, NULL,
+                           orig, NULL, src1, NULL, src2, NULL,
                            flag, marker_size);
        return 0;
 }
@@ -128,7 +132,7 @@ static void create_temp(mmfile_t *src, char *path)
 static int ll_ext_merge(const struct ll_merge_driver *fn,
                        mmbuffer_t *result,
                        const char *path,
-                       mmfile_t *orig,
+                       mmfile_t *orig, const char *orig_name,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
                        int flag, int marker_size)
@@ -319,7 +323,7 @@ static int git_path_check_merge(const char *path, struct git_attr_check check[2]
 
 int ll_merge(mmbuffer_t *result_buf,
             const char *path,
-            mmfile_t *ancestor,
+            mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
             int flag)
@@ -341,7 +345,7 @@ int ll_merge(mmbuffer_t *result_buf,
        driver = find_ll_merge_driver(ll_driver_name);
        if (virtual_ancestor && driver->recursive)
                driver = find_ll_merge_driver(driver->recursive);
-       return driver->fn(driver, result_buf, path, ancestor,
+       return driver->fn(driver, result_buf, path, ancestor, ancestor_label,
                          ours, our_label, theirs, their_label,
                          flag, marker_size);
 }
index 57889227b1782d3792be2046fbb54bca67b779de..57754cc8ca7b378a86b168a4fd6299fa3dfba045 100644 (file)
@@ -7,7 +7,7 @@
 
 int ll_merge(mmbuffer_t *result_buf,
             const char *path,
-            mmfile_t *ancestor,
+            mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
             int flag);
index fd34d76e1516b2c944778a11a5670d382f245873..c336c93c01c0bad76d6189065f0e6630d0b7f5af 100644 (file)
@@ -30,7 +30,13 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
        int merge_status;
        mmbuffer_t res;
 
-       merge_status = ll_merge(&res, path, base,
+       /*
+        * This function is only used by cmd_merge_tree, which
+        * does not respect the merge.conflictstyle option.
+        * There is no need to worry about a label for the
+        * common ancestor.
+        */
+       merge_status = ll_merge(&res, path, base, NULL,
                                our, ".our", their, ".their", 0);
        if (merge_status < 0)
                return NULL;
index 195ebf974435b0b08cd2be0f54c137218034008b..917397ca7a0c3a702681e1c3e93eb385bb6f28fb 100644 (file)
@@ -608,7 +608,7 @@ static int merge_3way(struct merge_options *o,
                      const char *branch2)
 {
        mmfile_t orig, src1, src2;
-       char *name1, *name2;
+       char *base_name, *name1, *name2;
        int merge_status;
        int favor;
 
@@ -628,10 +628,15 @@ static int merge_3way(struct merge_options *o,
                }
        }
 
-       if (strcmp(a->path, b->path)) {
+       if (strcmp(a->path, b->path) ||
+           (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
+               base_name = o->ancestor == NULL ? NULL :
+                       xstrdup(mkpath("%s:%s", o->ancestor, one->path));
                name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
                name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
        } else {
+               base_name = o->ancestor == NULL ? NULL :
+                       xstrdup(mkpath("%s", o->ancestor));
                name1 = xstrdup(mkpath("%s", branch1));
                name2 = xstrdup(mkpath("%s", branch2));
        }
@@ -640,7 +645,7 @@ static int merge_3way(struct merge_options *o,
        read_mmblob(&src1, a->sha1);
        read_mmblob(&src2, b->sha1);
 
-       merge_status = ll_merge(result_buf, a->path, &orig,
+       merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2,
                                (!!o->call_depth) | (favor << 1));
 
@@ -1342,6 +1347,7 @@ int merge_recursive(struct merge_options *o,
        if (!o->call_depth)
                read_cache();
 
+       o->ancestor = "merged common ancestors";
        clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
                            &mrtree);
 
index be8410ad1803bc10e5dbf74f39eecdfed53469b1..d1192f56d797a1664f5bfb5028d52ad679928e23 100644 (file)
@@ -4,6 +4,7 @@
 #include "string-list.h"
 
 struct merge_options {
+       const char *ancestor;
        const char *branch1;
        const char *branch2;
        enum {
diff --git a/notes.h b/notes.h
index ee65bd1a2430d4af53f03fd2cc9faa916863408c..9f59277c516f7ac78bcc66f91a7d7013b2a77f65 100644 (file)
--- a/notes.h
+++ b/notes.h
@@ -212,7 +212,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,
 struct string_list;
 
 struct display_notes_opt {
-       int suppress_default_notes:1;
+       unsigned int suppress_default_notes:1;
        struct string_list *extra_notes_refs;
 };
 
diff --git a/refs.c b/refs.c
index 0f24c8d5d9fa897c0b72c529c9fd2ccbcc7bd4d9..d3db15a76cc46f6f6a31d4448816c09e6c48e543 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1276,6 +1276,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
        if (log_all_ref_updates &&
            (!prefixcmp(ref_name, "refs/heads/") ||
             !prefixcmp(ref_name, "refs/remotes/") ||
+            !prefixcmp(ref_name, "refs/notes/") ||
             !strcmp(ref_name, "HEAD"))) {
                if (safe_create_leading_directories(log_file) < 0)
                        return error("unable to create directory for %s",
index a59f74f76c293efa783103eaf3d167c97b3768ea..f221bed1e97a0f1b41d1845edac270a109e3a4dd 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -319,7 +319,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
                if (!mmfile[i].ptr && !mmfile[i].size)
                        mmfile[i].ptr = xstrdup("");
        }
-       ll_merge(&result, path, &mmfile[0],
+       ll_merge(&result, path, &mmfile[0], NULL,
                 &mmfile[1], "ours",
                 &mmfile[2], "theirs", 0);
        for (i = 0; i < 3; i++)
@@ -376,7 +376,7 @@ static int merge(const char *name, const char *path)
                ret = 1;
                goto out;
        }
-       ret = ll_merge(&result, path, &base, &cur, "", &other, "", 0);
+       ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", 0);
        if (!ret) {
                FILE *f = fopen(path, "w");
                if (!f)
index a08a9d08808bdb2f4a138d7e6f602b61fc093c1b..ff65328006404fd0d113f2cd4c4d52377b4cc8cf 100644 (file)
@@ -2271,7 +2271,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
 }
 
 static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
-                             void *buf, unsigned long len, time_t mtime)
+                             const void *buf, unsigned long len, time_t mtime)
 {
        int fd, ret;
        unsigned char compressed[4096];
@@ -2307,7 +2307,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        git_SHA1_Update(&c, hdr, hdrlen);
 
        /* Then the data itself.. */
-       stream.next_in = buf;
+       stream.next_in = (void *)buf;
        stream.avail_in = len;
        do {
                unsigned char *in0 = stream.next_in;
@@ -2342,7 +2342,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        return move_temp_to_file(tmpfile, filename);
 }
 
-int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
        unsigned char sha1[20];
        char hdr[32];
index 1ac536e638dbbc02deb2d4e4a607cc52f7f7c108..c9ad7fcd49669b0dff481d9ab857bf70d8a51bca 100644 (file)
@@ -168,12 +168,19 @@ void sort_string_list(struct string_list *list)
        qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
 }
 
-int unsorted_string_list_has_string(struct string_list *list, const char *string)
+struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
+                                                    const char *string)
 {
        int i;
        for (i = 0; i < list->nr; i++)
                if (!strcmp(string, list->items[i].string))
-                       return 1;
-       return 0;
+                       return list->items + i;
+       return NULL;
+}
+
+int unsorted_string_list_has_string(struct string_list *list,
+                                   const char *string)
+{
+       return unsorted_string_list_lookup(list, string) != NULL;
 }
 
index 6569cf607b18b84f39ebee613471f270e42cfbdc..63b69c8d75ee33120a65a23598ddf93e84831bdd 100644 (file)
@@ -38,5 +38,6 @@ struct string_list_item *string_list_lookup(const char *string, struct string_li
 struct string_list_item *string_list_append(const char *string, struct string_list *list);
 void sort_string_list(struct string_list *list);
 int unsorted_string_list_has_string(struct string_list *list, const char *string);
-
+struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
+                                                    const char *string);
 #endif /* STRING_LIST_H */
index b3b8bc147909f81be6a387318ad0601dae50460f..676d48fb33119f393befcaf8998ad38741366525 100644 (file)
@@ -12,8 +12,15 @@ static int add_submodule_odb(const char *path)
        struct strbuf objects_directory = STRBUF_INIT;
        struct alternate_object_database *alt_odb;
        int ret = 0;
+       const char *git_dir;
 
-       strbuf_addf(&objects_directory, "%s/.git/objects/", path);
+       strbuf_addf(&objects_directory, "%s/.git", path);
+       git_dir = read_gitfile_gently(objects_directory.buf);
+       if (git_dir) {
+               strbuf_reset(&objects_directory);
+               strbuf_addstr(&objects_directory, git_dir);
+       }
+       strbuf_addstr(&objects_directory, "/objects/");
        if (!is_directory(objects_directory.buf)) {
                ret = -1;
                goto done;
@@ -132,7 +139,6 @@ void show_submodule_summary(FILE *f, const char *path,
 
 unsigned is_submodule_modified(const char *path, int ignore_untracked)
 {
-       int i;
        ssize_t len;
        struct child_process cp;
        const char *argv[] = {
@@ -141,16 +147,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
                NULL,
                NULL,
        };
-       const char *env[LOCAL_REPO_ENV_SIZE + 3];
        struct strbuf buf = STRBUF_INIT;
        unsigned dirty_submodule = 0;
        const char *line, *next_line;
+       const char *git_dir;
 
-       for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
-               env[i] = local_repo_env[i];
-
-       strbuf_addf(&buf, "%s/.git/", path);
-       if (!is_directory(buf.buf)) {
+       strbuf_addf(&buf, "%s/.git", path);
+       git_dir = read_gitfile_gently(buf.buf);
+       if (!git_dir)
+               git_dir = buf.buf;
+       if (!is_directory(git_dir)) {
                strbuf_release(&buf);
                /* The submodule is not checked out, so it is not modified */
                return 0;
@@ -158,21 +164,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        }
        strbuf_reset(&buf);
 
-       strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
-       env[i++] = strbuf_detach(&buf, NULL);
-       strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
-       env[i++] = strbuf_detach(&buf, NULL);
-       env[i] = NULL;
-
        if (ignore_untracked)
                argv[2] = "-uno";
 
        memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
-       cp.env = env;
+       cp.env = local_repo_env;
        cp.git_cmd = 1;
        cp.no_stdin = 1;
        cp.out = -1;
+       cp.dir = path;
        if (start_command(&cp))
                die("Could not run git status --porcelain");
 
@@ -201,8 +202,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        if (finish_command(&cp))
                die("git status --porcelain failed");
 
-       for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
-               free((char *)env[i]);
        strbuf_release(&buf);
        return dirty_submodule;
 }
index cc30be4a655cad98eac233b5da9fc585ddb5d055..055ad00f778eda1de02a418bbc602e580acdaca1 100755 (executable)
@@ -20,34 +20,23 @@ if ! setfacl -m u:root:rwx .; then
     test_done
 fi
 
-modebits () {
-       ls -l "$1" | sed -e 's|^\(..........\).*|\1|'
-}
-
 check_perms_and_acl () {
-       actual=$(modebits "$1") &&
-       case "$actual" in
-       -r--r-----*)
-               : happy
-               ;;
-       *)
-               echo "Got permission '$actual', expected '-r--r-----'"
-               false
-               ;;
-       esac &&
+       test -r "$1" &&
        getfacl "$1" > actual &&
        grep -q "user:root:rwx" actual &&
        grep -q "user:${LOGNAME}:rwx" actual &&
-       grep -q "mask::r--" actual &&
+       egrep "mask::?r--" actual > /dev/null 2>&1 &&
        grep -q "group::---" actual || false
 }
 
 dirs_to_set="./ .git/ .git/objects/ .git/objects/pack/"
 
 test_expect_success 'Setup test repo' '
+       setfacl -m d:u::rwx,d:g::---,d:o:---,d:m:rwx $dirs_to_set &&
+       setfacl -m m:rwx               $dirs_to_set &&
        setfacl -m u:root:rwx          $dirs_to_set &&
-       setfacl -d -m u:"$LOGNAME":rwx $dirs_to_set &&
-       setfacl -d -m u:root:rwx       $dirs_to_set &&
+       setfacl -m d:u:"$LOGNAME":rwx  $dirs_to_set &&
+       setfacl -m d:u:root:rwx        $dirs_to_set &&
 
        touch file.txt &&
        git add file.txt &&
index 1d6cd45b55a2ae2e0a7d6728b04112d1c0f43446..b2e7b0703979ce462455f19d4c3c82f02dc2540e 100755 (executable)
@@ -65,6 +65,15 @@ test_expect_success 'create notes' '
        test_must_fail git notes show HEAD^
 '
 
+cat >expect <<EOF
+d423f8c refs/notes/commits@{0}: notes: Notes added by 'git notes add'
+EOF
+
+test_expect_success 'create reflog entry' '
+       git reflog show refs/notes/commits >output &&
+       test_cmp expect output
+'
+
 test_expect_success 'edit existing notes' '
        MSG=b3 git notes edit &&
        test ! -f .git/NOTES_EDITMSG &&
index 19668c2c9206c5dfe63a5992bc7d011a9cdb4083..f20ea38411d0ca67709dbde0bfd1108e28c0dd71 100755 (executable)
@@ -22,12 +22,18 @@ set_fake_editor
 # | \
 # |   F - G - H                (branch1)
 # |     \
-#  \      I                    (branch2)
-#   \
-#     J - K - L - M            (no-conflict-branch)
+# |\      I                    (branch2)
+# | \
+# |   J - K - L - M            (no-conflict-branch)
+#  \
+#    N - O - P                 (no-ff-branch)
 #
 # where A, B, D and G all touch file1, and one, two, three, four all
 # touch file "conflict".
+#
+# WARNING: Modifications to the initial repository can change the SHA ID used
+# in the expect2 file for the 'stop on conflicting pick' test.
+
 
 test_expect_success 'setup' '
        test_commit A file1 &&
@@ -48,6 +54,11 @@ test_expect_success 'setup' '
        done &&
        git checkout -b no-conflict-branch A &&
        for n in J K L M
+       do
+               test_commit $n file$n
+       done &&
+       git checkout -b no-ff-branch A &&
+       for n in N O P
        do
                test_commit $n file$n
        done
@@ -113,7 +124,7 @@ cat > expect2 << EOF
 D
 =======
 G
->>>>>>> 51047de... G
+>>>>>>> 5d18e54... G
 EOF
 
 test_expect_success 'stop on conflicting pick' '
@@ -577,4 +588,30 @@ test_expect_success 'rebase -i can copy notes over a fixup' '
        test_cmp expect output
 '
 
+test_expect_success 'rebase while detaching HEAD' '
+       git symbolic-ref HEAD &&
+       grandparent=$(git rev-parse HEAD~2) &&
+       test_tick &&
+       FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
+       test $grandparent = $(git rev-parse HEAD~2) &&
+       test_must_fail git symbolic-ref HEAD
+'
+
+test_tick # Ensure that the rebased commits get a different timestamp.
+test_expect_success 'always cherry-pick with --no-ff' '
+       git checkout no-ff-branch &&
+       git tag original-no-ff-branch &&
+       git rebase -i --no-ff A &&
+       touch empty &&
+       for p in 0 1 2
+       do
+               test ! $(git rev-parse HEAD~$p) = $(git rev-parse original-no-ff-branch~$p) &&
+               git diff HEAD~$p original-no-ff-branch~$p > out &&
+               test_cmp empty out
+       done &&
+       test $(git rev-parse HEAD~3) = $(git rev-parse original-no-ff-branch~3) &&
+       git diff HEAD~3 original-no-ff-branch~3 > out &&
+       test_cmp empty out
+'
+
 test_done
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
new file mode 100644 (file)
index 0000000..e25cf80
--- /dev/null
@@ -0,0 +1,198 @@
+#!/bin/sh
+
+test_description='test cherry-pick and revert with conflicts
+
+  -
+  + picked: rewrites foo to c
+  + base: rewrites foo to b
+  + initial: writes foo as a, unrelated as unrelated
+
+'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       echo unrelated >unrelated &&
+       git add unrelated &&
+       test_commit initial foo a &&
+       test_commit base foo b &&
+       test_commit picked foo c &&
+       git config advice.detachedhead false
+
+'
+
+test_expect_success 'failed cherry-pick does not advance HEAD' '
+
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       head=$(git rev-parse HEAD) &&
+       test_must_fail git cherry-pick picked &&
+       newhead=$(git rev-parse HEAD) &&
+
+       test "$head" = "$newhead"
+'
+
+test_expect_success 'failed cherry-pick produces dirty index' '
+
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+
+       test_must_fail git update-index --refresh -q &&
+       test_must_fail git diff-index --exit-code HEAD
+'
+
+test_expect_success 'failed cherry-pick registers participants in index' '
+
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       {
+               git checkout base -- foo &&
+               git ls-files --stage foo &&
+               git checkout initial -- foo &&
+               git ls-files --stage foo &&
+               git checkout picked -- foo &&
+               git ls-files --stage foo
+       } > stages &&
+       sed "
+               1 s/ 0  / 1     /
+               2 s/ 0  / 2     /
+               3 s/ 0  / 3     /
+       " < stages > expected &&
+       git checkout -f initial^0 &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+       git ls-files --stage --unmerged > actual &&
+
+       test_cmp expected actual
+'
+
+test_expect_success 'failed cherry-pick describes conflict in work tree' '
+
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       =======
+       c
+       >>>>>>> objid picked
+       EOF
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'diff3 -m style' '
+
+       git config merge.conflictstyle diff3 &&
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       ||||||| parent of objid picked
+       b
+       =======
+       c
+       >>>>>>> objid picked
+       EOF
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'revert also handles conflicts sanely' '
+
+       git config --unset merge.conflictstyle &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       =======
+       b
+       >>>>>>> parent of objid picked
+       EOF
+       {
+               git checkout picked -- foo &&
+               git ls-files --stage foo &&
+               git checkout initial -- foo &&
+               git ls-files --stage foo &&
+               git checkout base -- foo &&
+               git ls-files --stage foo
+       } > stages &&
+       sed "
+               1 s/ 0  / 1     /
+               2 s/ 0  / 2     /
+               3 s/ 0  / 3     /
+       " < stages > expected-stages &&
+       git checkout -f initial^0 &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       head=$(git rev-parse HEAD) &&
+       test_must_fail git revert picked &&
+       newhead=$(git rev-parse HEAD) &&
+       git ls-files --stage --unmerged > actual-stages &&
+
+       test "$head" = "$newhead" &&
+       test_must_fail git update-index --refresh -q &&
+       test_must_fail git diff-index --exit-code HEAD &&
+       test_cmp expected-stages actual-stages &&
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'revert conflict, diff3 -m style' '
+       git config merge.conflictstyle diff3 &&
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       ||||||| objid picked
+       c
+       =======
+       b
+       >>>>>>> parent of objid picked
+       EOF
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git revert picked &&
+
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_done
index 0391a5827ea8ba196b7796b7df818f8ac860c387..61589853df55e063fbe6489fc9c6effc4a9f33b6 100755 (executable)
@@ -120,7 +120,6 @@ test_expect_success '--check with --no-pager returns 2 for dirty difference' '
 
 '
 
-
 test_expect_success 'check should test not just the last line' '
        echo "" >>a &&
        git --no-pager diff --check
@@ -142,4 +141,26 @@ test_expect_success 'check detects leftover conflict markers' '
        git reset --hard
 '
 
+test_expect_success 'check honors conflict marker length' '
+       git reset --hard &&
+       echo ">>>>>>> boo" >>b &&
+       echo "======" >>a &&
+       git diff --check a &&
+       (
+               git diff --check b
+               test $? = 2
+       ) &&
+       git reset --hard &&
+       echo ">>>>>>>> boo" >>b &&
+       echo "========" >>a &&
+       git diff --check &&
+       echo "b conflict-marker-size=8" >.gitattributes &&
+       (
+               git diff --check b
+               test $? = 2
+       ) &&
+       git diff --check a &&
+       git reset --hard
+'
+
 test_done
index 11b19972ca89f20faaa35b8a2c9fcd7f97181f78..019acb926d6765bf24e1dfe4bea2a9dba28ca797 100755 (executable)
@@ -329,4 +329,19 @@ index 0000000..$head7
 EOF
 "
 
+test_expect_success 'setup .git file for sm2' '
+       (cd sm2 &&
+        REAL="$(pwd)/../.real" &&
+        mv .git "$REAL"
+        echo "gitdir: $REAL" >.git)
+'
+
+test_expect_success 'diff --submodule with .git file' '
+       git diff --submodule HEAD^ >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+'
+
 test_done
index 26920502093a98d4b5721f783e006de9d999792a..230c0cd784b317856749609cf64a5067e35a6965 100755 (executable)
@@ -110,17 +110,18 @@ test_expect_success 'remove remote' '
 test_expect_success 'remove remote protects non-remote branches' '
 (
        cd test &&
-       (cat >expect1 <<EOF
+       cat >expect1 <<EOF
 Note: A non-remote branch was not removed; to delete it, use:
   git branch -d master
 EOF
-    cat >expect2 <<EOF
+       } &&
+       { cat >expect2 <<EOF
 Note: Non-remote branches were not removed; to delete them, use:
   git branch -d foobranch
   git branch -d master
 EOF
-) &&
-       git tag footag
+       } &&
+       git tag footag &&
        git config --add remote.oops.fetch "+refs/*:refs/*" &&
        git remote rm oops 2>actual1 &&
        git branch foobranch &&
@@ -534,43 +535,34 @@ test_expect_success 'show empty remote' '
 '
 
 test_expect_success 'new remote' '
-(
        git remote add someremote foo &&
        echo foo >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url bar' '
-(
        git remote set-url someremote bar &&
        echo bar >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url baz bar' '
-(
        git remote set-url someremote baz bar &&
        echo baz >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url zot bar' '
-(
        test_must_fail git remote set-url someremote zot bar &&
        echo baz >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push zot baz' '
-(
        test_must_fail git remote set-url --push someremote zot baz &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -578,11 +570,9 @@ test_expect_success 'remote set-url --push zot baz' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push zot' '
-(
        git remote set-url --push someremote zot &&
        echo zot >expect &&
        echo "YYY" >>expect &&
@@ -591,11 +581,9 @@ test_expect_success 'remote set-url --push zot' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push qux zot' '
-(
        git remote set-url --push someremote qux zot &&
        echo qux >expect &&
        echo "YYY" >>expect &&
@@ -604,11 +592,9 @@ test_expect_success 'remote set-url --push qux zot' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push foo qu+x' '
-(
        git remote set-url --push someremote foo qu+x &&
        echo foo >expect &&
        echo "YYY" >>expect &&
@@ -617,11 +603,9 @@ test_expect_success 'remote set-url --push foo qu+x' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push --add aaa' '
-(
        git remote set-url --push --add someremote aaa &&
        echo foo >expect &&
        echo aaa >>expect &&
@@ -631,11 +615,9 @@ test_expect_success 'remote set-url --push --add aaa' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push bar aaa' '
-(
        git remote set-url --push someremote bar aaa &&
        echo foo >expect &&
        echo bar >>expect &&
@@ -645,11 +627,9 @@ test_expect_success 'remote set-url --push bar aaa' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push --delete bar' '
-(
        git remote set-url --push --delete someremote bar &&
        echo foo >expect &&
        echo "YYY" >>expect &&
@@ -658,11 +638,9 @@ test_expect_success 'remote set-url --push --delete bar' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push --delete foo' '
-(
        git remote set-url --push --delete someremote foo &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -670,11 +648,9 @@ test_expect_success 'remote set-url --push --delete foo' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --add bbb' '
-(
        git remote set-url --add someremote bbb &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -683,12 +659,10 @@ test_expect_success 'remote set-url --add bbb' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete .*' '
-(
-       test_must_fail git remote set-url --delete someremote .* &&
+       test_must_fail git remote set-url --delete someremote .\* &&
        echo "YYY" >expect &&
        echo baz >>expect &&
        echo bbb >>expect &&
@@ -696,11 +670,9 @@ test_expect_success 'remote set-url --delete .*' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete bbb' '
-(
        git remote set-url --delete someremote bbb &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -708,11 +680,9 @@ test_expect_success 'remote set-url --delete bbb' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete baz' '
-(
        test_must_fail git remote set-url --delete someremote baz &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -720,11 +690,9 @@ test_expect_success 'remote set-url --delete baz' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --add ccc' '
-(
        git remote set-url --add someremote ccc &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -733,11 +701,9 @@ test_expect_success 'remote set-url --add ccc' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete baz' '
-(
        git remote set-url --delete someremote baz &&
        echo "YYY" >expect &&
        echo ccc >>expect &&
@@ -745,7 +711,6 @@ test_expect_success 'remote set-url --delete baz' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_done
index b0047d3c6b593795561ce908ab8e10ff574d3dbc..d24ca5c077a0cd036645adb23795f1c75fba5d5a 100755 (executable)
@@ -209,4 +209,13 @@ test_expect_success '%gd shortens ref name' '
        test_cmp expect.gd-short actual.gd-short
 '
 
+test_expect_success 'oneline with empty message' '
+       git commit -m "dummy" --allow-empty &&
+       git commit -m "dummy" --allow-empty &&
+       git filter-branch --msg-filter "sed -e s/dummy//" HEAD^^.. &&
+       git rev-list --oneline HEAD > /tmp/test.txt &&
+       test $(git rev-list --oneline HEAD | wc -l) -eq 5 &&
+       test $(git rev-list --oneline --graph HEAD | wc -l) -eq 5
+'
+
 test_done
index 5034dd1352c275beca4d5dae805cad6573a89aca..d486d73994cf563063b578ec5e212331e87bf67f 100755 (executable)
@@ -181,7 +181,7 @@ et nihil mihi deerit;
 
 In loco pascuae ibi me collocavit;
 super aquam refectionis educavit me.
-|||||||
+||||||| new5.txt
 et nihil mihi deerit.
 In loco pascuae ibi me collocavit,
 super aquam refectionis educavit me;
@@ -225,7 +225,7 @@ et nihil mihi deerit;
 
 In loco pascuae ibi me collocavit;
 super aquam refectionis educavit me.
-||||||||||
+|||||||||| new5.txt
 et nihil mihi deerit.
 In loco pascuae ibi me collocavit,
 super aquam refectionis educavit me;
index 42f6fff373ba9707216279011b112c6c59af8780..42f8ece0978f38e10200a52ce8cf1952cf13ecbd 100755 (executable)
@@ -7,65 +7,69 @@ test_description='fmt-merge-msg test'
 
 . ./test-lib.sh
 
-datestamp=1151939923
-setdate () {
-       GIT_COMMITTER_DATE="$datestamp +0200"
-       GIT_AUTHOR_DATE="$datestamp +0200"
-       datestamp=`expr "$datestamp" + 1`
-       export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-}
-
 test_expect_success setup '
        echo one >one &&
        git add one &&
-       setdate &&
+       test_tick &&
        git commit -m "Initial" &&
 
+       git clone . remote &&
+
        echo uno >one &&
        echo dos >two &&
        git add two &&
-       setdate &&
+       test_tick &&
        git commit -a -m "Second" &&
 
        git checkout -b left &&
 
-       echo $datestamp >one &&
-       setdate &&
+       echo "c1" >one &&
+       test_tick &&
        git commit -a -m "Common #1" &&
 
-       echo $datestamp >one &&
-       setdate &&
+       echo "c2" >one &&
+       test_tick &&
        git commit -a -m "Common #2" &&
 
        git branch right &&
 
-       echo $datestamp >two &&
-       setdate &&
+       echo "l3" >two &&
+       test_tick &&
        git commit -a -m "Left #3" &&
 
-       echo $datestamp >two &&
-       setdate &&
+       echo "l4" >two &&
+       test_tick &&
        git commit -a -m "Left #4" &&
 
-       echo $datestamp >two &&
-       setdate &&
+       echo "l5" >two &&
+       test_tick &&
        git commit -a -m "Left #5" &&
+       git tag tag-l5 &&
 
        git checkout right &&
 
-       echo $datestamp >three &&
+       echo "r3" >three &&
        git add three &&
-       setdate &&
+       test_tick &&
        git commit -a -m "Right #3" &&
+       git tag tag-r3 &&
 
-       echo $datestamp >three &&
-       setdate &&
+       echo "r4" >three &&
+       test_tick &&
        git commit -a -m "Right #4" &&
 
-       echo $datestamp >three &&
-       setdate &&
+       echo "r5" >three &&
+       test_tick &&
        git commit -a -m "Right #5" &&
 
+       git checkout -b long &&
+       i=0 &&
+       while test $i -lt 30
+       do
+               test_commit $i one &&
+               i=$(($i+1))
+       done &&
+
        git show-branch
 '
 
@@ -113,7 +117,7 @@ test_expect_success 'merge-msg test #3-1' '
        git config merge.log true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -127,7 +131,7 @@ test_expect_success 'merge-msg test #3-2' '
        git config merge.summary true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -159,7 +163,7 @@ test_expect_success 'merge-msg test #4-1' '
        git config merge.log true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -173,7 +177,7 @@ test_expect_success 'merge-msg test #4-2' '
        git config merge.summary true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -187,7 +191,7 @@ test_expect_success 'merge-msg test #5-1' '
        git config merge.log yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -201,7 +205,7 @@ test_expect_success 'merge-msg test #5-2' '
        git config merge.summary yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -215,7 +219,7 @@ test_expect_success 'merge-msg -F' '
        git config merge.summary yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
@@ -229,7 +233,7 @@ test_expect_success 'merge-msg -F in subdirectory' '
        git config merge.summary yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
        mkdir sub &&
        cp .git/FETCH_HEAD sub/FETCH_HEAD &&
@@ -240,4 +244,128 @@ test_expect_success 'merge-msg -F in subdirectory' '
        test_cmp expected actual
 '
 
+test_expect_success 'merge-msg with nothing to merge' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       (
+               cd remote &&
+               git checkout -b unrelated &&
+               test_tick &&
+               git fetch origin &&
+               git fmt-merge-msg <.git/FETCH_HEAD >../actual
+       ) &&
+
+       test_cmp /dev/null actual
+'
+
+cat >expected <<\EOF
+Merge tag 'tag-r3'
+
+* tag 'tag-r3':
+  Right #3
+  Common #2
+  Common #1
+EOF
+
+test_expect_success 'merge-msg tag' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       test_tick &&
+       git fetch . tag tag-r3 &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge tags 'tag-r3' and 'tag-l5'
+
+* tag 'tag-r3':
+  Right #3
+  Common #2
+  Common #1
+
+* tag 'tag-l5':
+  Left #5
+  Left #4
+  Left #3
+  Common #2
+  Common #1
+EOF
+
+test_expect_success 'merge-msg two tags' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       test_tick &&
+       git fetch . tag tag-r3 tag tag-l5 &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge branch 'left', tag 'tag-r3'
+
+* tag 'tag-r3':
+  Right #3
+  Common #2
+  Common #1
+
+* left:
+  Left #5
+  Left #4
+  Left #3
+  Common #2
+  Common #1
+EOF
+
+test_expect_success 'merge-msg tag and branch' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       test_tick &&
+       git fetch . tag tag-r3 left &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge branch 'long'
+
+* long: (35 commits)
+EOF
+
+test_expect_success 'merge-msg lots of commits' '
+
+       git checkout master &&
+       test_tick &&
+       git fetch . long &&
+
+       i=29 &&
+       while test $i -gt 9
+       do
+               echo "  $i" &&
+               i=$(($i-1))
+       done >>expected &&
+       echo "  ..." >>expected
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
 test_done
index d20ed61b481539b25c054c49bd82aa6fb9b3a981..1337fa5a2209d489c43f0a34c95a89053d3fd8bf 100755 (executable)
@@ -11,10 +11,12 @@ Test switching across them.
   ! [master] Initial A one, A two
    * [renamer] Renamer R one->uno, M two
     ! [side] Side M one, D two, A three
-  ---
-    + [side] Side M one, D two, A three
-   *  [renamer] Renamer R one->uno, M two
-  +*+ [master] Initial A one, A two
+     ! [simple] Simple D one, M two
+  ----
+     + [simple] Simple D one, M two
+    +  [side] Side M one, D two, A three
+   *   [renamer] Renamer R one->uno, M two
+  +*++ [master] Initial A one, A two
 
 '
 
@@ -52,6 +54,11 @@ test_expect_success setup '
        git update-index --add --remove one two three &&
        git commit -m "Side M one, D two, A three" &&
 
+       git checkout -b simple master &&
+       rm -f one &&
+       fill a c e > two &&
+       git commit -a -m "Simple D one, M two" &&
+
        git checkout master
 '
 
@@ -166,6 +173,56 @@ test_expect_success 'checkout -m with merge conflict' '
        ! test -s current
 '
 
+test_expect_success 'format of merge conflict from checkout -m' '
+
+       git checkout -f master && git clean -f &&
+
+       fill b d > two &&
+       git checkout -m simple &&
+
+       git ls-files >current &&
+       fill same two two two >expect &&
+       test_cmp current expect &&
+
+       cat <<-EOF >expect &&
+       <<<<<<< simple
+       a
+       c
+       e
+       =======
+       b
+       d
+       >>>>>>> local
+       EOF
+       test_cmp two expect
+'
+
+test_expect_success 'checkout --merge --conflict=diff3 <branch>' '
+
+       git checkout -f master && git reset --hard && git clean -f &&
+
+       fill b d > two &&
+       git checkout --merge --conflict=diff3 simple &&
+
+       cat <<-EOF >expect &&
+       <<<<<<< simple
+       a
+       c
+       e
+       ||||||| master
+       a
+       b
+       c
+       d
+       e
+       =======
+       b
+       d
+       >>>>>>> local
+       EOF
+       test_cmp two expect
+'
+
 test_expect_success 'checkout to detach HEAD (with advice declined)' '
 
        git config advice.detachedHead false &&
@@ -481,7 +538,7 @@ test_expect_success 'checkout with --merge, in diff3 -m style' '
        (
                echo "<<<<<<< ours"
                echo ourside
-               echo "|||||||"
+               echo "||||||| base"
                echo original
                echo "======="
                echo theirside
@@ -525,7 +582,7 @@ test_expect_success 'checkout --conflict=diff3' '
        (
                echo "<<<<<<< ours"
                echo ourside
-               echo "|||||||"
+               echo "||||||| base"
                echo original
                echo "======="
                echo theirside
index aeec1f6142e622ffc7b0ef8a68fe7734c02d24d0..3d4f85d74f6f378d76bde77e581273af010ba452 100755 (executable)
@@ -157,6 +157,22 @@ test_expect_success 'status with added and untracked file in modified submodule
        EOF
 '
 
+test_expect_success 'setup .git file for sub' '
+       (cd sub &&
+        rm -f new-file
+        REAL="$(pwd)/../.real" &&
+        mv .git "$REAL"
+        echo "gitdir: $REAL" >.git) &&
+        echo .real >>.gitignore &&
+        git commit -m "added .real to .gitignore" .gitignore
+'
+
+test_expect_success 'status with added file in modified submodule with .git file' '
+       (cd sub && git reset --hard && echo >foo && git add foo) &&
+       git status >output &&
+       grep "modified:   sub (new commits, modified content)" output
+'
+
 test_expect_success 'rm submodule contents' '
        rm -rf sub/* sub/.git
 '
index 408f0137a8342414eedba3a02372ea1ad6050117..d22a71a3999b3dc0e99f5e36053447b33f967bd7 100644 (file)
@@ -11,6 +11,16 @@ prefix ?= $(HOME)
 template_instdir ?= $(prefix)/share/git-core/templates
 # DESTDIR=
 
+ifndef SHELL_PATH
+       SHELL_PATH = /bin/sh
+endif
+ifndef PERL_PATH
+       PERL_PATH = perl
+endif
+
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+
 # Shell quote (do not use $(call) to accommodate ancient setups);
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 template_instdir_SQ = $(subst ','\'',$(template_instdir))
@@ -33,8 +43,11 @@ boilerplates.made : $(bpsrc)
                case "$$boilerplate" in \
                *--) continue;; \
                esac && \
-               cp $$boilerplate blt/$$dst && \
-               if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \
+               sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+                   -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
+                   -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' $$boilerplate > \
+                       blt/$$dst && \
+               if test -x "$$boilerplate"; then rx=rx; else rx=r; fi && \
                chmod a+$$rx "blt/$$dst" || exit; \
        done && \
        date >$@
index 6ef1d29d09a10a5b6c3cbec0ac481931cd0d85fc..b58d1184a9d43a39c0d95f32453efc78581877d6 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # An example hook script to check the commit log message.
-# Called by git-commit with one argument, the name of the file
+# Called by "git commit" with one argument, the name of the file
 # that has the commit message.  The hook should exit with non-zero
 # status after issuing an appropriate message if it wants to stop the
 # commit.  The hook is allowed to edit the commit message file.
index 5323b56b81b9dd3d7f9fb86d8892241becbb5e7e..ec17ec1939b7c3e86b7cb6c0c4de6b0818a7e75e 100755 (executable)
@@ -5,4 +5,4 @@
 #
 # To enable this hook, rename this file to "post-update".
 
-exec git-update-server-info
+exec git update-server-info
index 439eefda510ca8de9f55c63616f2113ac36c8b6b..b187c4bb1f256e19c25f80dd64f3451ced77e123 100755 (executable)
@@ -1,13 +1,13 @@
 #!/bin/sh
 #
 # An example hook script to verify what is about to be committed.
-# Called by git-commit with no arguments.  The hook should
+# Called by "git commit" with no arguments.  The hook should
 # exit with non-zero status after issuing an appropriate message if
 # it wants to stop the commit.
 #
 # To enable this hook, rename this file to "pre-commit".
 
-if git-rev-parse --verify HEAD >/dev/null 2>&1
+if git rev-parse --verify HEAD >/dev/null 2>&1
 then
        against=HEAD
 else
index be1b06e25043146f22261b55548229e6ab524b7c..053f1111c0d734c057e895cdc992188104cc4f84 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Copyright (c) 2006, 2008 Junio C Hamano
 #
-# The "pre-rebase" hook is run just before "git-rebase" starts doing
+# The "pre-rebase" hook is run just before "git rebase" starts doing
 # its job, and can prevent the command from running by exiting with
 # non-zero status.
 #
@@ -43,7 +43,7 @@ git show-ref -q "$topic" || {
 }
 
 # Is topic fully merged to master?
-not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
+not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
 if test -z "$not_in_master"
 then
        echo >&2 "$topic is fully merged to master; better remove it."
@@ -51,11 +51,11 @@ then
 fi
 
 # Is topic ever merged to next?  If so you should not be rebasing it.
-only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
-only_next_2=`git-rev-list ^master           ${publish} | sort`
+only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git rev-list ^master           ${publish} | sort`
 if test "$only_next_1" = "$only_next_2"
 then
-       not_in_topic=`git-rev-list "^$topic" master`
+       not_in_topic=`git rev-list "^$topic" master`
        if test -z "$not_in_topic"
        then
                echo >&2 "$topic is already up-to-date with master"
@@ -64,8 +64,8 @@ then
                exit 0
        fi
 else
-       not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
-       perl -e '
+       not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
+       @PERL_PATH@ -e '
                my $topic = $ARGV[0];
                my $msg = "* $topic has commits already merged to public branch:\n";
                my (%not_in_next) = map {
@@ -157,13 +157,13 @@ B to be deleted.
 
 To compute (1):
 
-       git-rev-list ^master ^topic next
-       git-rev-list ^master        next
+       git rev-list ^master ^topic next
+       git rev-list ^master        next
 
        if these match, topic has not merged in next at all.
 
 To compute (2):
 
-       git-rev-list master..topic
+       git rev-list master..topic
 
        if this is empty, it is fully merged to "master".
index 365242499dcf0ee35c26ccb2917724d6e559be69..86b8f227ecab874a4af98bc5ba3164d370e5e4b5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # An example hook script to prepare the commit log message.
-# Called by git-commit with the name of the file that has the
+# Called by "git commit" with the name of the file that has the
 # commit message, followed by the description of the commit
 # message's source.  The hook's purpose is to edit the commit
 # message file.  If the hook fails with a non-zero status,
 
 case "$2,$3" in
   merge,)
-    perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+    @PERL_PATH@ -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
 
 # ,|template,)
-#   perl -i.bak -pe '
+#   @PERL_PATH@ -i.bak -pe '
 #      print "\n" . `git diff --cached --name-status -r`
 #       if /^#/ && $first++ == 0' "$1" ;;
 
index fd63b2d662dbcf98ec622a1ab754d041a559e3be..71ab04edc09be7aeefa1e8a0f609a974ffd55a9f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # An example hook script to blocks unannotated tags from entering.
-# Called by git-receive-pack with arguments: refname sha1-old sha1-new
+# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
 #
 # To enable this hook, rename this file to "update".
 #
@@ -64,7 +64,7 @@ zero="0000000000000000000000000000000000000000"
 if [ "$newrev" = "$zero" ]; then
        newrev_type=delete
 else
-       newrev_type=$(git-cat-file -t $newrev)
+       newrev_type=$(git cat-file -t $newrev)
 fi
 
 case "$refname","$newrev_type" in
index 2c87b72dff61f8394b3f1f32e21c1d936314ec2e..a5196d1be8fb59edf8062bef36d3a602e0812139 100644 (file)
@@ -1,4 +1,4 @@
-# git-ls-files --others --exclude-from=.git/info/exclude
+# git ls-files --others --exclude-from=.git/info/exclude
 # Lines that start with '#' are comments.
 # For a project mostly in C, the following would be a good set of
 # exclude patterns (uncomment them if you want to use them):
index a71763ade835fd93ef291106298647408ada08e9..711048ea36dda1d814b395efa8bc69ab142425ca 100644 (file)
@@ -117,12 +117,14 @@ typedef struct s_xmparam {
        int level;
        int favor;
        int style;
+       const char *ancestor;   /* label for orig */
+       const char *file1;      /* label for mf1 */
+       const char *file2;      /* label for mf2 */
 } xmparam_t;
 
 #define DEFAULT_CONFLICT_MARKER_SIZE 7
 
-int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
-               mmfile_t *mf2, const char *name2,
+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
                xmparam_t const *xmp, mmbuffer_t *result);
 
 #ifdef __cplusplus
index 87cafa7021468d00a11c72dfdc1df05f1ede0fea..16dd9acd37b431f1e439d9ab051fe2436c54b45c 100644 (file)
@@ -145,11 +145,13 @@ static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 
 static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                              xdfenv_t *xe2, const char *name2,
+                             const char *name3,
                              int size, int i, int style,
                              xdmerge_t *m, char *dest, int marker_size)
 {
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
+       int marker3_size = (name3 ? strlen(name3) + 1 : 0);
        int j;
 
        if (marker_size <= 0)
@@ -179,10 +181,15 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        if (style == XDL_MERGE_DIFF3) {
                /* Shared preimage */
                if (!dest) {
-                       size += marker_size + 1;
+                       size += marker_size + 1 + marker3_size;
                } else {
                        for (j = 0; j < marker_size; j++)
                                dest[size++] = '|';
+                       if (marker3_size) {
+                               dest[size] = ' ';
+                               memcpy(dest + size + 1, name3, marker3_size - 1);
+                               size += marker3_size;
+                       }
                        dest[size++] = '\n';
                }
                size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
@@ -217,6 +224,7 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
 
 static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                                 xdfenv_t *xe2, const char *name2,
+                                const char *ancestor_name,
                                 int favor,
                                 xdmerge_t *m, char *dest, int style,
                                 int marker_size)
@@ -229,6 +237,7 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
 
                if (m->mode == 0)
                        size = fill_conflict_hunk(xe1, name1, xe2, name2,
+                                                 ancestor_name,
                                                  size, i, style, m, dest,
                                                  marker_size);
                else if (m->mode & 3) {
@@ -398,11 +407,15 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
  *
  * returns < 0 on error, == 0 for no conflicts, else number of conflicts
  */
-static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
-               xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
-               xmparam_t const *xmp, mmbuffer_t *result) {
+static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
+               xdfenv_t *xe2, xdchange_t *xscr2,
+               xmparam_t const *xmp, mmbuffer_t *result)
+{
        xdmerge_t *changes, *c;
        xpparam_t const *xpp = &xmp->xpp;
+       const char *const ancestor_name = xmp->ancestor;
+       const char *const name1 = xmp->file1;
+       const char *const name2 = xmp->file2;
        int i0, i1, i2, chg0, chg1, chg2;
        int level = xmp->level;
        int style = xmp->style;
@@ -540,6 +553,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
        if (result) {
                int marker_size = xmp->marker_size;
                int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
+                                                ancestor_name,
                                                 favor, changes, NULL, style,
                                                 marker_size);
                result->ptr = xdl_malloc(size);
@@ -548,15 +562,16 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
                        return -1;
                }
                result->size = size;
-               xdl_fill_merge_buffer(xe1, name1, xe2, name2, favor, changes,
+               xdl_fill_merge_buffer(xe1, name1, xe2, name2,
+                                     ancestor_name, favor, changes,
                                      result->ptr, style, marker_size);
        }
        return xdl_cleanup_merge(changes);
 }
 
-int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
-               mmfile_t *mf2, const char *name2,
-               xmparam_t const *xmp, mmbuffer_t *result) {
+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
+               xmparam_t const *xmp, mmbuffer_t *result)
+{
        xdchange_t *xscr1, *xscr2;
        xdfenv_t xe1, xe2;
        int status;
@@ -591,8 +606,8 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
                memcpy(result->ptr, mf1->ptr, mf1->size);
                result->size = mf1->size;
        } else {
-               status = xdl_do_merge(&xe1, xscr1, name1,
-                                     &xe2, xscr2, name2,
+               status = xdl_do_merge(&xe1, xscr1,
+                                     &xe2, xscr2,
                                      xmp, result);
        }
        xdl_free_script(xscr1);