Merge branch 'sb/fmt-merge-msg'
authorJunio C Hamano <gitster@pobox.com>
Tue, 6 Apr 2010 21:50:46 +0000 (14:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 6 Apr 2010 21:50:46 +0000 (14:50 -0700)
* sb/fmt-merge-msg:
fmt-merge-msg: hide summary option
fmt-merge-msg: remove custom string_list implementation
string-list: add unsorted_string_list_lookup()
fmt-merge-msg: use pretty.c routines
t6200: test fmt-merge-msg more
t6200: modernize with test_tick
fmt-merge-msg: be quiet if nothing to merge

82 files changed:
.mailmap
Documentation/RelNotes-1.7.0.4.txt [new file with mode: 0644]
Documentation/RelNotes-1.7.1.txt
Documentation/everyday.txt
Documentation/git-cherry-pick.txt
Documentation/git-http-backend.txt
Documentation/git-imap-send.txt
Documentation/git-rebase.txt
Documentation/git-show-ref.txt
Documentation/git.txt
Documentation/howto/revert-a-faulty-merge.txt
Documentation/technical/pack-protocol.txt
GIT-VERSION-GEN
Makefile
builtin/checkout.c
builtin/commit.c
builtin/fast-export.c
builtin/grep.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/merge-file.c
builtin/merge.c
builtin/notes.c
builtin/reset.c
builtin/rev-list.c
builtin/revert.c
cache.h
compat/bswap.h
compat/mingw.c
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-difftool.perl
git-rebase--interactive.sh
git-rebase.sh
git-send-email.perl
git-stash.sh
git_remote_helpers/Makefile
gitweb/gitweb.perl
grep.c
http-backend.c
imap-send.c
ll-merge.c
ll-merge.h
merge-file.c
merge-recursive.c
merge-recursive.h
parse-options.c
parse-options.h
rerere.c
t/t1304-default-acl.sh
t/t3301-notes.sh
t/t3404-rebase-interactive.sh
t/t3506-cherry-pick-ff.sh [new file with mode: 0755]
t/t3507-cherry-pick-conflict.sh [new file with mode: 0644]
t/t4014-format-patch.sh
t/t4017-diff-retval.sh
t/t5407-post-rewrite-hook.sh
t/t5505-remote.sh
t/t6006-rev-list-format.sh
t/t6023-merge-file.sh
t/t7201-co.sh
t/t7800-difftool.sh
t/t9350-fast-export.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>
diff --git a/Documentation/RelNotes-1.7.0.4.txt b/Documentation/RelNotes-1.7.0.4.txt
new file mode 100644 (file)
index 0000000..cf7f60e
--- /dev/null
@@ -0,0 +1,27 @@
+Git v1.7.0.4 Release Notes
+==========================
+
+Fixes since v1.7.0.3
+--------------------
+
+ * Optimized ntohl/htonl on big-endian machines were broken.
+
+ * Color values given to "color.<cmd>.<slot>" configuration can now have
+   more than one attributes (e.g. "bold ul").
+
+ * "git add -u nonexistent-path" did not complain.
+
+ * "git apply --whitespace=fix" didn't work well when an early patch in
+   a patch series adds trailing blank lines and a later one depended on
+   such a block of blank lines at the end.
+
+ * "git fast-export" didn't check error status and stop when marks file
+   cannot be opened.
+
+ * "git format-patch --ignore-if-in-upstream" gave unwarranted errors
+   when the range was empty, instead of silently finishing.
+
+ * "git remote prune" did not detect remote tracking refs that became
+   dangling correctly.
+
+And other minor fixes and documentation updates.
index 750d40f34ad36680640d6efd98b59ba6dc7900be..19aeef5effd16a7a7fc5409ca42bc54eb780e991 100644 (file)
@@ -7,19 +7,14 @@ Updates since v1.7.0
  * Some commands (e.g. svn and http interfaces) that interactively ask
    password can be told to use an external program given via GIT_ASKPASS.
 
- * Color values given to "color.<cmd>.<slot>" configuration can now have
-   more than one attributes (e.g. "bold ul").
-
- * "git apply --whitespace=fix" didn't work well when an early patch in
-   a patch series adds trailing blank lines and a later one depended on
-   such a block of blank lines at the end.
-
  * "git am" learned "--keep-cr" option to handle inputs that are
    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 for-each-ref" learned %(symref), %(symref:short) and %(flag)
    tokens.
 
@@ -36,11 +31,15 @@ Updates since v1.7.0
 
  * "git grep" learned to paint filename and line-number in colors.
 
+ * "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 notes" command has been rewritten in C and learned quite a
-   many commands.
+   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.
@@ -49,6 +48,8 @@ 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 svn" should work better when interacting with repositories
    with CRLF line endings.
 
@@ -66,5 +67,5 @@ release, unless otherwise noted.
 ---
 exec >/var/tmp/1
 echo O=$(git describe)
-O=v1.7.0.2-323-g0d0925c
+O=v1.7.0.3-310-g99f5b08
 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 78f4714da0c226b9523f60f247f60ab13119c7c7..d71607a85d03062c76f7d17d4fd8e8b4168a279d 100644 (file)
@@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit
 
 SYNOPSIS
 --------
-'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] <commit>
+'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>
 
 DESCRIPTION
 -----------
@@ -70,6 +70,10 @@ effect to your index in a row.
 --signoff::
        Add Signed-off-by line at the end of the commit message.
 
+--ff::
+       If the current HEAD is the same as the parent of the
+       cherry-pick'ed commit, then a fast forward to this commit will
+       be performed.
 
 Author
 ------
index 52388206570238636d50ed360120d3464f630a94..277d9e141bf81bddb4ba661e43763b7774a1417d 100644 (file)
@@ -35,7 +35,7 @@ These services can be enabled/disabled using the per-repository
 configuration file:
 
 http.getanyfile::
-       This serves older Git clients which are unable to use the
+       This serves Git clients older than version 1.6.6 that are unable to use the
        upload pack service.  When enabled, clients are able to read
        any file within the repository, including objects that are
        no longer reachable from a branch but are still present.
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 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 df17d49b87c260c6f5b3fd75d4aad41b77fcf8c3..3f9d9c6db39e030c82e1159043c45c834a47012c 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git show-ref' [-q|--quiet] [--verify] [--head] [-d|--dereference]
             [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags]
-            [--heads] [--] <pattern>...
+            [--heads] [--] [<pattern>...]
 'git show-ref' --exclude-existing[=<pattern>] < ref-list
 
 DESCRIPTION
index 4e00b315ff7450efb4a48ba184c6d65991d53c58..657eac831cf0650ce3c4ac6a1f6a690b282cea59 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.7.0.3/git.html[documentation for release 1.7.0.3]
+* link:v1.7.0.4/git.html[documentation for release 1.7.0.4]
 
 * release notes for
+  link:RelNotes-1.7.0.4.txt[1.7.0.4],
   link:RelNotes-1.7.0.3.txt[1.7.0.3],
   link:RelNotes-1.7.0.2.txt[1.7.0.2],
   link:RelNotes-1.7.0.1.txt[1.7.0.1],
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 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 076c18ecc3fc9dc77d1be5dc6e960da72c519576..3eb6d8517eeda1e51d042363f0265fc87f4e5ba0 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.0.3
+DEF_VER=v1.7.0.4
 
 LF='
 '
index 3a6c6ea5259693db4846b91855675218b1e1a920..9d850f49200c3611d054e0e96519675aef126a31 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
@@ -1476,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:
        @$$(:)
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 b0a4029c94d1bdb1c673fe604cdbfec93df875aa..c6dd71a7bcd0dfcb4691c9ca66a0c3a7bd4dcaae 100644 (file)
@@ -503,7 +503,7 @@ static void export_marks(char *file)
 
        f = fopen(file, "w");
        if (!f)
-               error("Unable to open marks file %s for writing.", file);
+               die_errno("Unable to open marks file %s for writing.", file);
 
        for (i = 0; i < idnums.size; i++) {
                if (deco->base && deco->base->type == 1) {
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 a8dd8c989c5a135e14c6fc06ea3b23f4f0cd0bec..b706a5ff88ec185e63c0aacd109bb16cc54027e3 100644 (file)
@@ -1157,8 +1157,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        return 0;
        }
 
-       if (ignore_if_in_upstream)
+       if (ignore_if_in_upstream) {
+               /* Don't say anything if head and upstream are the same. */
+               if (rev.pending.nr == 2) {
+                       struct object_array_entry *o = rev.pending.objects;
+                       if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
+                               return 0;
+               }
                get_patch_ids(&rev, &ids, prefix);
+       }
 
        if (!use_stdout)
                realstdout = xfdopen(xdup(1), "w");
@@ -1296,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;
@@ -1308,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);
@@ -1337,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;
@@ -1390,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 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 3aaec7bed76af9efdfe5647be0da64373db2011e..c043066845e03e47093f88ca0b01c7bdef7bffdd 100644 (file)
@@ -667,7 +667,7 @@ static int count_unmerged_entries(void)
        return ret;
 }
 
-static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
+int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)
 {
        struct tree *trees[MAX_UNPACK_TREES];
        struct unpack_trees_options opts;
index 4543d113113f90d7fb262b5fe54cbe5f6dfe29fd..52b72fca687d42dc09d1d79a8e76584a55c0c546 100644 (file)
 #include "string-list.h"
 
 static const char * const git_notes_usage[] = {
+       "git notes [--ref <notes_ref>] [list [<object>]]",
+       "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+       "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
+       "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+       "git notes [--ref <notes_ref>] edit [<object>]",
+       "git notes [--ref <notes_ref>] show [<object>]",
+       "git notes [--ref <notes_ref>] remove [<object>]",
+       "git notes [--ref <notes_ref>] prune",
+       NULL
+};
+
+static const char * const git_notes_list_usage[] = {
        "git notes [list [<object>]]",
-       "git notes add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
-       "git notes copy [-f] <from-object> <to-object>",
-       "git notes append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+       NULL
+};
+
+static const char * const git_notes_add_usage[] = {
+       "git notes add [<options>] [<object>]",
+       NULL
+};
+
+static const char * const git_notes_copy_usage[] = {
+       "git notes copy [<options>] <from-object> <to-object>",
+       "git notes copy --stdin [<from-object> <to-object>]...",
+       NULL
+};
+
+static const char * const git_notes_append_usage[] = {
+       "git notes append [<options>] [<object>]",
+       NULL
+};
+
+static const char * const git_notes_edit_usage[] = {
        "git notes edit [<object>]",
+       NULL
+};
+
+static const char * const git_notes_show_usage[] = {
        "git notes show [<object>]",
+       NULL
+};
+
+static const char * const git_notes_remove_usage[] = {
        "git notes remove [<object>]",
+       NULL
+};
+
+static const char * const git_notes_prune_usage[] = {
        "git notes prune",
        NULL
 };
@@ -272,7 +313,6 @@ int commit_notes(struct notes_tree *t, const char *msg)
        return 0;
 }
 
-
 combine_notes_fn *parse_combine_notes_fn(const char *v)
 {
        if (!strcasecmp(v, "overwrite"))
@@ -427,22 +467,65 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd)
        return ret;
 }
 
-int cmd_notes(int argc, const char **argv, const char *prefix)
+static struct notes_tree *init_notes_check(const char *subcommand)
+{
+       struct notes_tree *t;
+       init_notes(NULL, NULL, NULL, 0);
+       t = &default_notes_tree;
+
+       if (prefixcmp(t->ref, "refs/notes/"))
+               die("Refusing to %s notes in %s (outside of refs/notes/)",
+                   subcommand, t->ref);
+       return t;
+}
+
+static int list(int argc, const char **argv, const char *prefix)
 {
        struct notes_tree *t;
-       unsigned char object[20], from_obj[20], new_note[20];
+       unsigned char object[20];
        const unsigned char *note;
+       int retval = -1;
+       struct option options[] = {
+               OPT_END()
+       };
+
+       if (argc)
+               argc = parse_options(argc, argv, prefix, options,
+                                    git_notes_list_usage, 0);
+
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_list_usage, options);
+       }
+
+       t = init_notes_check("list");
+       if (argc) {
+               if (get_sha1(argv[0], object))
+                       die("Failed to resolve '%s' as a valid ref.", argv[0]);
+               note = get_note(t, object);
+               if (note) {
+                       puts(sha1_to_hex(note));
+                       retval = 0;
+               } else
+                       retval = error("No note found for object %s.",
+                                      sha1_to_hex(object));
+       } else
+               retval = for_each_note(t, 0, list_each_note, NULL);
+
+       free_notes(t);
+       return retval;
+}
+
+static int add(int argc, const char **argv, const char *prefix)
+{
+       int retval = 0, force = 0;
        const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20], new_note[20];
        char logmsg[100];
-
-       int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,
-           remove = 0, prune = 0, force = 0, from_stdin = 0;
-       int given_object = 0, i = 1, retval = 0;
+       const unsigned char *note;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
-       const char *rewrite_cmd = NULL;
-       const char *override_notes_ref = NULL;
        struct option options[] = {
-               OPT_GROUP("Notes contents options"),
                { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
                        "note contents as a string", PARSE_OPT_NONEG,
                        parse_msg_arg},
@@ -455,196 +538,325 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
                        "reuse specified note object", PARSE_OPT_NONEG,
                        parse_reuse_arg},
-               OPT_GROUP("Other options"),
                OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
-               OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
-               OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
-                          "use notes from <notes_ref>"),
-               OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
-                          "load rewriting config for <command> (implies --stdin)"),
                OPT_END()
        };
 
-       git_config(git_default_config, NULL);
+       argc = parse_options(argc, argv, prefix, options, git_notes_add_usage,
+                            0);
 
-       argc = parse_options(argc, argv, prefix, options, git_notes_usage, 0);
-
-       if (override_notes_ref) {
-               struct strbuf sb = STRBUF_INIT;
-               if (!prefixcmp(override_notes_ref, "refs/notes/"))
-                       /* we're happy */;
-               else if (!prefixcmp(override_notes_ref, "notes/"))
-                       strbuf_addstr(&sb, "refs/");
-               else
-                       strbuf_addstr(&sb, "refs/notes/");
-               strbuf_addstr(&sb, override_notes_ref);
-               setenv("GIT_NOTES_REF", sb.buf, 1);
-               strbuf_release(&sb);
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_add_usage, options);
        }
 
-       if (argc && !strcmp(argv[0], "list"))
-               list = 1;
-       else if (argc && !strcmp(argv[0], "add"))
-               add = 1;
-       else if (argc && !strcmp(argv[0], "copy"))
-               copy = 1;
-       else if (argc && !strcmp(argv[0], "append"))
-               append = 1;
-       else if (argc && !strcmp(argv[0], "edit"))
-               edit = 1;
-       else if (argc && !strcmp(argv[0], "show"))
-               show = 1;
-       else if (argc && !strcmp(argv[0], "remove"))
-               remove = 1;
-       else if (argc && !strcmp(argv[0], "prune"))
-               prune = 1;
-       else if (!argc) {
-               list = 1; /* Default to 'list' if no other subcommand given */
-               i = 0;
-       }
+       object_ref = argc ? argv[0] : "HEAD";
 
-       if (list + add + copy + append + edit + show + remove + prune != 1)
-               usage_with_options(git_notes_usage, options);
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
 
-       if (msg.given && !(add || append || edit)) {
-               error("cannot use -m/-F/-c/-C options with %s subcommand.",
-                     argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
+       t = init_notes_check("add");
+       note = get_note(t, object);
 
-       if (msg.given && edit) {
-               fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
-                       "for the 'edit' subcommand.\n"
-                       "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
+       if (note) {
+               if (!force) {
+                       retval = error("Cannot add notes. Found existing notes "
+                                      "for object %s. Use '-f' to overwrite "
+                                      "existing notes", sha1_to_hex(object));
+                       goto out;
+               }
+               fprintf(stderr, "Overwriting existing notes for object %s\n",
+                       sha1_to_hex(object));
        }
 
-       if (force && !(add || copy)) {
-               error("cannot use -f option with %s subcommand.", argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
+       create_note(object, &msg, 0, note, new_note);
 
-       if (!copy && rewrite_cmd) {
-               error("cannot use --for-rewrite with %s subcommand.", argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
-       if (!copy && from_stdin) {
-               error("cannot use --stdin with %s subcommand.", argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
+       if (is_null_sha1(new_note))
+               remove_note(t, object);
+       else
+               add_note(t, object, new_note, combine_notes_overwrite);
 
-       if (copy) {
-               const char *from_ref;
-               if (from_stdin || rewrite_cmd) {
-                       if (argc > 1) {
-                               error("too many parameters");
-                               usage_with_options(git_notes_usage, options);
-                       } else {
-                               return notes_copy_from_stdin(force, rewrite_cmd);
-                       }
-               }
-               if (argc < 3) {
-                       error("too few parameters");
-                       usage_with_options(git_notes_usage, options);
+       snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
+                is_null_sha1(new_note) ? "removed" : "added", "add");
+       commit_notes(t, logmsg);
+out:
+       free_notes(t);
+       strbuf_release(&(msg.buf));
+       return retval;
+}
+
+static int copy(int argc, const char **argv, const char *prefix)
+{
+       int retval = 0, force = 0, from_stdin = 0;
+       const unsigned char *from_note, *note;
+       const char *object_ref;
+       unsigned char object[20], from_obj[20];
+       struct notes_tree *t;
+       const char *rewrite_cmd = NULL;
+       struct option options[] = {
+               OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
+               OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
+               OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
+                          "load rewriting config for <command> (implies "
+                          "--stdin)"),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage,
+                            0);
+
+       if (from_stdin || rewrite_cmd) {
+               if (argc) {
+                       error("too many parameters");
+                       usage_with_options(git_notes_copy_usage, options);
+               } else {
+                       return notes_copy_from_stdin(force, rewrite_cmd);
                }
-               from_ref = argv[i++];
-               if (get_sha1(from_ref, from_obj))
-                       die("Failed to resolve '%s' as a valid ref.", from_ref);
        }
 
-       given_object = argc > i;
-       object_ref = given_object ? argv[i++] : "HEAD";
-
-       if (argc > i || (prune && given_object)) {
+       if (2 < argc) {
                error("too many parameters");
-               usage_with_options(git_notes_usage, options);
+               usage_with_options(git_notes_copy_usage, options);
        }
 
-       if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+       if (get_sha1(argv[0], from_obj))
+               die("Failed to resolve '%s' as a valid ref.", argv[0]);
 
-       init_notes(NULL, NULL, NULL, 0);
-       t = &default_notes_tree;
+       object_ref = 1 < argc ? argv[1] : "HEAD";
 
-       if (prefixcmp(t->ref, "refs/notes/"))
-               die("Refusing to %s notes in %s (outside of refs/notes/)",
-                   argv[0], t->ref);
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
 
+       t = init_notes_check("copy");
        note = get_note(t, object);
 
-       /* list command */
-
-       if (list) {
-               if (given_object) {
-                       if (note) {
-                               puts(sha1_to_hex(note));
-                               goto end;
-                       }
-               } else {
-                       retval = for_each_note(t, 0, list_each_note, NULL);
-                       goto end;
+       if (note) {
+               if (!force) {
+                       retval = error("Cannot copy notes. Found existing "
+                                      "notes for object %s. Use '-f' to "
+                                      "overwrite existing notes",
+                                      sha1_to_hex(object));
+                       goto out;
                }
+               fprintf(stderr, "Overwriting existing notes for object %s\n",
+                       sha1_to_hex(object));
        }
 
-       /* show command */
-
-       if ((list || show) && !note) {
-               error("No note found for object %s.", sha1_to_hex(object));
-               retval = 1;
-               goto end;
-       } else if (show) {
-               const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
-               retval = execv_git_cmd(show_args);
-               goto end;
+       from_note = get_note(t, from_obj);
+       if (!from_note) {
+               retval = error("Missing notes on source object %s. Cannot "
+                              "copy.", sha1_to_hex(from_obj));
+               goto out;
        }
 
-       /* add/append/edit/remove/prune command */
+       add_note(t, object, from_note, combine_notes_overwrite);
+       commit_notes(t, "Notes added by 'git notes copy'");
+out:
+       free_notes(t);
+       return retval;
+}
 
-       if ((add || copy) && note) {
-               if (!force) {
-                       error("Cannot %s notes. Found existing notes for object"
-                             " %s. Use '-f' to overwrite existing notes",
-                             argv[0], sha1_to_hex(object));
-                       retval = 1;
-                       goto end;
-               }
-               fprintf(stderr, "Overwriting existing notes for object %s\n",
-                       sha1_to_hex(object));
-       }
+static int append_edit(int argc, const char **argv, const char *prefix)
+{
+       const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20], new_note[20];
+       const unsigned char *note;
+       char logmsg[100];
+       const char * const *usage;
+       struct msg_arg msg = { 0, 0, STRBUF_INIT };
+       struct option options[] = {
+               { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
+                       "note contents as a string", PARSE_OPT_NONEG,
+                       parse_msg_arg},
+               { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
+                       "note contents in a file", PARSE_OPT_NONEG,
+                       parse_file_arg},
+               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
+                       "reuse and edit specified note object", PARSE_OPT_NONEG,
+                       parse_reedit_arg},
+               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
+                       "reuse specified note object", PARSE_OPT_NONEG,
+                       parse_reuse_arg},
+               OPT_END()
+       };
+       int edit = !strcmp(argv[0], "edit");
+
+       usage = edit ? git_notes_edit_usage : git_notes_append_usage;
+       argc = parse_options(argc, argv, prefix, options, usage,
+                            PARSE_OPT_KEEP_ARGV0);
 
-       if (remove) {
-               msg.given = 1;
-               msg.use_editor = 0;
-               strbuf_reset(&(msg.buf));
+       if (2 < argc) {
+               error("too many parameters");
+               usage_with_options(usage, options);
        }
 
-       if (prune) {
-               hashclr(new_note);
-               prune_notes(t);
-               goto commit;
-       } else if (copy) {
-               const unsigned char *from_note = get_note(t, from_obj);
-               if (!from_note) {
-                       error("Missing notes on source object %s. Cannot copy.",
-                             sha1_to_hex(from_obj));
-                       retval = 1;
-                       goto end;
-               }
-               hashcpy(new_note, from_note);
-       } else
-               create_note(object, &msg, append, note, new_note);
+       if (msg.given && edit)
+               fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
+                       "for the 'edit' subcommand.\n"
+                       "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
+
+       object_ref = 1 < argc ? argv[1] : "HEAD";
+
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+       t = init_notes_check(argv[0]);
+       note = get_note(t, object);
+
+       create_note(object, &msg, !edit, note, new_note);
 
        if (is_null_sha1(new_note))
                remove_note(t, object);
        else
                add_note(t, object, new_note, combine_notes_overwrite);
 
-commit:
        snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
                 is_null_sha1(new_note) ? "removed" : "added", argv[0]);
        commit_notes(t, logmsg);
-
-end:
        free_notes(t);
        strbuf_release(&(msg.buf));
+       return 0;
+}
+
+static int show(int argc, const char **argv, const char *prefix)
+{
+       const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20];
+       const unsigned char *note;
+       int retval;
+       struct option options[] = {
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options, git_notes_show_usage,
+                            0);
+
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_show_usage, options);
+       }
+
+       object_ref = argc ? argv[0] : "HEAD";
+
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+       t = init_notes_check("show");
+       note = get_note(t, object);
+
+       if (!note)
+               retval = error("No note found for object %s.",
+                              sha1_to_hex(object));
+       else {
+               const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
+               retval = execv_git_cmd(show_args);
+       }
+       free_notes(t);
        return retval;
 }
+
+static int remove_cmd(int argc, const char **argv, const char *prefix)
+{
+       struct option options[] = {
+               OPT_END()
+       };
+       const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20];
+
+       argc = parse_options(argc, argv, prefix, options,
+                            git_notes_remove_usage, 0);
+
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_remove_usage, options);
+       }
+
+       object_ref = argc ? argv[0] : "HEAD";
+
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+       t = init_notes_check("remove");
+
+       fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object));
+       remove_note(t, object);
+
+       commit_notes(t, "Notes removed by 'git notes remove'");
+       free_notes(t);
+       return 0;
+}
+
+static int prune(int argc, const char **argv, const char *prefix)
+{
+       struct notes_tree *t;
+       struct option options[] = {
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage,
+                            0);
+
+       if (argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_prune_usage, options);
+       }
+
+       t = init_notes_check("prune");
+
+       prune_notes(t);
+       commit_notes(t, "Notes removed by 'git notes prune'");
+       free_notes(t);
+       return 0;
+}
+
+int cmd_notes(int argc, const char **argv, const char *prefix)
+{
+       int result;
+       const char *override_notes_ref = NULL;
+       struct option options[] = {
+               OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
+                          "use notes from <notes_ref>"),
+               OPT_END()
+       };
+
+       git_config(git_default_config, NULL);
+       argc = parse_options(argc, argv, prefix, options, git_notes_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (override_notes_ref) {
+               struct strbuf sb = STRBUF_INIT;
+               if (!prefixcmp(override_notes_ref, "refs/notes/"))
+                       /* we're happy */;
+               else if (!prefixcmp(override_notes_ref, "notes/"))
+                       strbuf_addstr(&sb, "refs/");
+               else
+                       strbuf_addstr(&sb, "refs/notes/");
+               strbuf_addstr(&sb, override_notes_ref);
+               setenv("GIT_NOTES_REF", sb.buf, 1);
+               strbuf_release(&sb);
+       }
+
+       if (argc < 1 || !strcmp(argv[0], "list"))
+               result = list(argc, argv, prefix);
+       else if (!strcmp(argv[0], "add"))
+               result = add(argc, argv, prefix);
+       else if (!strcmp(argv[0], "copy"))
+               result = copy(argc, argv, prefix);
+       else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit"))
+               result = append_edit(argc, argv, prefix);
+       else if (!strcmp(argv[0], "show"))
+               result = show(argc, argv, prefix);
+       else if (!strcmp(argv[0], "remove"))
+               result = remove_cmd(argc, argv, prefix);
+       else if (!strcmp(argv[0], "prune"))
+               result = prune(argc, argv, prefix);
+       else {
+               result = error("Unknown subcommand: %s", argv[0]);
+               usage_with_options(git_notes_usage, options);
+       }
+
+       return result ? 1 : 0;
+}
index 2c3a69adc674bb3f539d29b2d29116e89f887066..1283068fd24c371e39f0271d01dd6b3aac437d4b 100644 (file)
@@ -23,7 +23,8 @@
 
 static const char * const git_reset_usage[] = {
        "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]",
-       "git reset [--mixed] <commit> [--] <paths>...",
+       "git reset [-q] <commit> [--] <paths>...",
+       "git reset --patch [<commit>] [--] [<paths>...]",
        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 eff52687a87b45b766e064eede7c2c35b6d133d2..778a56eb512edde3aac6c2a4d668cc73ab3d8460 100644 (file)
@@ -13,6 +13,7 @@
 #include "revision.h"
 #include "rerere.h"
 #include "merge-recursive.h"
+#include "refs.h"
 
 /*
  * This implements the builtins revert and cherry-pick.
@@ -35,7 +36,7 @@ static const char * const cherry_pick_usage[] = {
        NULL
 };
 
-static int edit, no_replay, no_commit, mainline, signoff;
+static int edit, no_replay, no_commit, mainline, signoff, allow_ff;
 static enum { REVERT, CHERRY_PICK } action;
 static struct commit *commit;
 static const char *commit_name;
@@ -45,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 =
@@ -60,8 +63,19 @@ static void parse_args(int argc, const char **argv)
                OPT_INTEGER('m', "mainline", &mainline, "parent number"),
                OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
                OPT_END(),
+               OPT_END(),
+               OPT_END(),
        };
 
+       if (action == CHERRY_PICK) {
+               struct option cp_extra[] = {
+                       OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"),
+                       OPT_END(),
+               };
+               if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
+                       die("program error");
+       }
+
        if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1)
                usage_with_options(usage_str, options);
 
@@ -73,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)
@@ -244,14 +289,25 @@ static NORETURN void die_dirty_index(const char *me)
        }
 }
 
+static int fast_forward_to(const unsigned char *to, const unsigned char *from)
+{
+       struct ref_lock *ref_lock;
+
+       read_cache();
+       if (checkout_fast_forward(from, to))
+               exit(1); /* the callee should have complained already */
+       ref_lock = lock_any_ref_for_update("HEAD", from, 0);
+       return write_ref_sha1(ref_lock, to, "cherry-pick");
+}
+
 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;
-       char *defmsg = git_pathdup("MERGE_MSG");
+       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;
        static struct lock_file index_lock;
@@ -265,6 +321,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        if (action == REVERT && !no_replay)
                die("revert is incompatible with replay");
 
+       if (allow_ff) {
+               if (signoff)
+                       die("cherry-pick --ff cannot be used with --signoff");
+               if (no_commit)
+                       die("cherry-pick --ff cannot be used with --no-commit");
+               if (no_replay)
+                       die("cherry-pick --ff cannot be used with -x");
+               if (edit)
+                       die("cherry-pick --ff cannot be used with --edit");
+       }
+
        if (read_cache() < 0)
                die("git %s: failed to read the index", me);
        if (no_commit) {
@@ -284,8 +351,6 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        }
        discard_cache();
 
-       index_fd = hold_locked_index(&index_lock, 1);
-
        if (!commit->parents) {
                if (action == REVERT)
                        die ("Cannot revert a root commit");
@@ -314,14 +379,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        else
                parent = commit->parents->item;
 
-       if (!(message = commit->buffer))
-               die ("Cannot get commit message for %s",
-                               sha1_to_hex(commit->object.sha1));
+       if (allow_ff && !hashcmp(parent->object.sha1, head))
+               return fast_forward_to(commit->object.sha1, head);
 
        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"
@@ -329,27 +397,19 @@ static int revert_or_cherry_pick(int argc, const char **argv)
         * reverse of it if we are revert.
         */
 
+       defmsg = git_pathdup("MERGE_MSG");
        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));
 
@@ -360,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));
@@ -372,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();
@@ -437,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 2928107bb135004e11f6a11a625067545680b62a..6dcb100a6cfc1b1d311602507bc3dcb483c1558d 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1058,4 +1058,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix);
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 
+/* builtin/merge.c */
+int checkout_fast_forward(const unsigned char *from, const unsigned char *to);
+
 #endif /* CACHE_H */
index f3b8c44181776a99c3eb79e15542104d67001c9d..54756dbb05ba99ab1679f17a50f04c3f1cede8e6 100644 (file)
@@ -17,6 +17,8 @@ static inline uint32_t default_swab32(uint32_t val)
                ((val & 0x000000ff) << 24));
 }
 
+#undef bswap32
+
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
 #define bswap32(x) ({ \
index c5bfb39b3949430cd06093afdbc85ecc22f8c9c7..30716903f5c3072588ddaae71f557f14d7806fde 100644 (file)
@@ -275,8 +275,17 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
        int fh, rc;
 
        /* must have write permission */
-       if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0)
-               return -1;
+       DWORD attrs = GetFileAttributes(file_name);
+       if (attrs != INVALID_FILE_ATTRIBUTES &&
+           (attrs & FILE_ATTRIBUTE_READONLY)) {
+               /* ignore errors here; open() will report them */
+               SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+       }
+
+       if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+               rc = -1;
+               goto revert_attrs;
+       }
 
        time_t_to_filetime(times->modtime, &mft);
        time_t_to_filetime(times->actime, &aft);
@@ -286,6 +295,13 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
        } else
                rc = 0;
        close(fh);
+
+revert_attrs:
+       if (attrs != INVALID_FILE_ATTRIBUTES &&
+           (attrs & FILE_ATTRIBUTE_READONLY)) {
+               /* ignore errors again */
+               SetFileAttributes(file_name, attrs);
+       }
        return rc;
 }
 
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 f5d93e9694d2f5e78bfa3d8dc886968d7cdd5867..167e6a4abda105ec1c4b4ddc58867a57ca506ba2 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
@@ -1370,37 +1371,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 +1404,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 +1413,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 +1857,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");
@@ -3883,6 +3881,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        const char **arg = argv;
        struct child_process child;
        struct strbuf buf = STRBUF_INIT;
+       int err = 0;
 
        temp = prepare_temp_file(spec->path, spec);
        *arg++ = pgm;
@@ -3893,16 +3892,20 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        child.use_shell = 1;
        child.argv = argv;
        child.out = -1;
-       if (start_command(&child) != 0 ||
-           strbuf_read(&buf, child.out, 0) < 0 ||
-           finish_command(&child) != 0) {
-               close(child.out);
-               strbuf_release(&buf);
+       if (start_command(&child)) {
                remove_tempfile();
-               error("error running textconv command '%s'", pgm);
                return NULL;
        }
+
+       if (strbuf_read(&buf, child.out, 0) < 0)
+               err = error("error reading from textconv command '%s'", pgm);
        close(child.out);
+
+       if (finish_command(&child) || err) {
+               strbuf_release(&buf);
+               remove_tempfile();
+               return NULL;
+       }
        remove_tempfile();
 
        return strbuf_detach(&buf, outsize);
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 d975d072dbf0fab36266c3f3a71a69875206e4d8..adc42de8752fd395707f1e395c61991b3146cebb 100755 (executable)
@@ -78,11 +78,13 @@ sub generate_command
                        next;
                }
                if ($arg eq '-g' || $arg eq '--gui') {
-                       my $tool = Git::command_oneline('config',
-                                                       'diff.guitool');
-                       if (length($tool)) {
-                               $ENV{GIT_DIFF_TOOL} = $tool;
-                       }
+                       eval {
+                               my $tool = Git::command_oneline('config',
+                                                               'diff.guitool');
+                               if (length($tool)) {
+                                       $ENV{GIT_DIFF_TOOL} = $tool;
+                               }
+                       };
                        next;
                }
                if ($arg eq '-y' || $arg eq '--no-prompt') {
index 415ae72dbc298d7723cdd23b1396c8a6d24dbe08..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
@@ -230,8 +232,9 @@ do_with_author () {
 }
 
 pick_one () {
-       no_ff=
-       case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac
+       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
@@ -240,16 +243,7 @@ pick_one () {
                output git cherry-pick "$@"
                return
        fi
-       parent_sha1=$(git rev-parse --verify $sha1^) ||
-               die "Could not get the parent of $sha1"
-       current_sha1=$(git rev-parse --verify HEAD)
-       if test -z "$no_ff" && test "$current_sha1" = "$parent_sha1"
-       then
-               output git reset --hard $sha1
-               output warn Fast-forward to $(git rev-parse --short $sha1)
-       else
-               output git cherry-pick "$@"
-       fi
+       output git cherry-pick $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -484,7 +478,7 @@ do_next () {
                mark_action_done
                pick_one $sha1 ||
                        die_with_patch $sha1 "Could not apply $sha1... $rest"
-               echo "$1" > "$DOTEST"/stopped-sha
+               echo "$sha1" > "$DOTEST"/stopped-sha
                make_patch $sha1
                git rev-parse --verify HEAD > "$AMEND"
                warn "Stopped at $sha1... $rest"
@@ -732,9 +726,10 @@ first and then run 'git rebase --continue' again."
                                test -n "$amend" && git reset --soft $amend
                                die "Could not commit staged changes."
                        }
-                       record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
                fi
 
+               record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
+
                require_clean_work_tree
                do_rest
                ;;
@@ -790,6 +785,9 @@ first and then run 'git rebase --continue' again."
        -i)
                # yeah, we know
                ;;
+       --no-ff)
+               NEVER_FF=t
+               ;;
        --root)
                REBASE_ROOT=t
                ;;
@@ -831,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
@@ -975,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 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)
index a2d2283ec921acac7b068537eb85f63c16de9556..c356e95f18f0f784584ce644c08e1966ca1be52f 100755 (executable)
@@ -2216,8 +2216,7 @@ sub config_to_multi {
 sub git_get_project_config {
        my ($key, $type) = @_;
 
-       # do we have project
-       return unless (defined $project && defined $git_dir);
+       return unless defined $git_dir;
 
        # key sanity check
        return unless ($key);
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 aeb2985b831c982f10c3905f5053136520fcc4fe..9d0097ca02960460ff3a104f1739982fee453987 100644 (file)
@@ -1226,9 +1226,6 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
                        fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host);
                        goto bail;
                }
-               if (!imap->buf.sock.ssl)
-                       imap_warn("*** IMAP Warning *** Password is being "
-                                 "sent in the clear\n");
 
                if (srvc->auth_method) {
                        struct imap_cmd_cb cb;
@@ -1253,6 +1250,9 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
                                goto bail;
                        }
                } else {
+                       if (!imap->buf.sock.ssl)
+                               imap_warn("*** IMAP Warning *** Password is being "
+                                         "sent in the clear\n");
                        if (imap_exec(ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass) != RESP_OK) {
                                fprintf(stderr, "IMAP error: LOGIN failed\n");
                                goto bail;
@@ -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 {
index c83035d013d3f50e9367f2b07d49cf17a1e22ff6..8546d8526f311e2a2703c258a4da3f02f8650df4 100644 (file)
@@ -659,3 +659,18 @@ int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
        *target = unset ? 2 : 1;
        return 0;
 }
+
+int parse_options_concat(struct option *dst, size_t dst_size, struct option *src)
+{
+       int i, j;
+
+       for (i = 0; i < dst_size; i++)
+               if (dst[i].type == OPTION_END)
+                       break;
+       for (j = 0; i < dst_size; i++, j++) {
+               dst[i] = src[j];
+               if (src[j].type == OPTION_END)
+                       return 0;
+       }
+       return -1;
+}
index 9429f7e36112b7b9cf52d4b3b68b007938396322..7581e931da13151473739036a89d9d19303eb18b 100644 (file)
@@ -187,6 +187,7 @@ extern int parse_options_step(struct parse_opt_ctx_t *ctx,
 
 extern int parse_options_end(struct parse_opt_ctx_t *ctx);
 
+extern int parse_options_concat(struct option *dst, size_t, struct option *src);
 
 /*----- some often used options -----*/
 extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
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 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 a4a0b1d6c58a7ae2762de6a907b4138238e95a48..1d6cd45b55a2ae2e0a7d6728b04112d1c0f43446 100755 (executable)
@@ -378,6 +378,17 @@ test_expect_success 'append to existing note with "git notes append"' '
        test_cmp expect output
 '
 
+cat > expect_list << EOF
+c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75
+c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5
+4b6ad22357cc8a1296720574b8d2fbc22fab0671 bd1753200303d0a0344be813e504253b3d98e74d
+EOF
+
+test_expect_success '"git notes list" does not expand to "git notes list HEAD"' '
+       git notes list > output &&
+       test_cmp expect_list output
+'
+
 test_expect_success 'appending empty string does not change existing note' '
        git notes append -m "" &&
        git notes show > output &&
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/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh
new file mode 100755 (executable)
index 0000000..e17ae71
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+test_description='test cherry-picking with --ff option'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo first > file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit -m "first" &&
+       git tag first &&
+
+       git checkout -b other &&
+       echo second >> file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit -m "second" &&
+       git tag second
+'
+
+test_expect_success 'cherry-pick using --ff fast forwards' '
+       git checkout master &&
+       git reset --hard first &&
+       test_tick &&
+       git cherry-pick --ff second &&
+       test "$(git rev-parse --verify HEAD)" = "$(git rev-parse --verify second)"
+'
+
+test_expect_success 'cherry-pick not using --ff does not fast forwards' '
+       git checkout master &&
+       git reset --hard first &&
+       test_tick &&
+       git cherry-pick second &&
+       test "$(git rev-parse --verify HEAD)" != "$(git rev-parse --verify second)"
+'
+
+#
+# We setup the following graph:
+#
+#            B---C
+#           /   /
+#      first---A
+#
+# (This has been taken from t3502-cherry-pick-merge.sh)
+#
+test_expect_success 'merge setup' '
+       git checkout master &&
+       git reset --hard first &&
+       echo new line >A &&
+       git add A &&
+       test_tick &&
+       git commit -m "add line to A" A &&
+       git tag A &&
+       git checkout -b side first &&
+       echo new line >B &&
+       git add B &&
+       test_tick &&
+       git commit -m "add line to B" B &&
+       git tag B &&
+       git checkout master &&
+       git merge side &&
+       git tag C &&
+       git checkout -b new A
+'
+
+test_expect_success 'cherry-pick a non-merge with --ff and -m should fail' '
+       git reset --hard A -- &&
+       test_must_fail git cherry-pick --ff -m 1 B &&
+       git diff --exit-code A --
+'
+
+test_expect_success 'cherry pick a merge with --ff but without -m should fail' '
+       git reset --hard A -- &&
+       test_must_fail git cherry-pick --ff C &&
+       git diff --exit-code A --
+'
+
+test_expect_success 'cherry pick with --ff a merge (1)' '
+       git reset --hard A -- &&
+       git cherry-pick --ff -m 1 C &&
+       git diff --exit-code C &&
+       test "$(git rev-parse --verify HEAD)" = "$(git rev-parse --verify C)"
+'
+
+test_expect_success 'cherry pick with --ff a merge (2)' '
+       git reset --hard B -- &&
+       git cherry-pick --ff -m 2 C &&
+       git diff --exit-code C &&
+       test "$(git rev-parse --verify HEAD)" = "$(git rev-parse --verify C)"
+'
+
+test_expect_success 'cherry pick a merge relative to nonexistent parent with --ff should fail' '
+       git reset --hard B -- &&
+       test_must_fail git cherry-pick --ff -m 3 C
+'
+
+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 c7b625642dd57f4bcb6f7c5aa240cc9c32e15af8..d21c37f3a20c42b05044e45c5e5af71294c8420c 100755 (executable)
@@ -609,4 +609,8 @@ test_expect_success 'format-patch -- <path>' '
        ! grep "Use .--" error
 '
 
+test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
+       git format-patch --ignore-if-in-upstream HEAD
+'
+
 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 f0f91f149d760f6b6458d10639725259973d7115..552da65a61e8f78d40f8e19cfc5b73696ebcf283 100755 (executable)
@@ -180,4 +180,20 @@ EOF
        verify_hook_input
 '
 
+test_expect_success 'git rebase -i (double edit)' '
+       git reset --hard D &&
+       clear_hook_input &&
+       FAKE_LINES="edit 1 edit 2" git rebase -i B &&
+       git rebase --continue &&
+       echo something > foo &&
+       git add foo &&
+       git rebase --continue &&
+       echo rebase >expected.args &&
+       cat >expected.data <<EOF &&
+$(git rev-parse C) $(git rev-parse HEAD^)
+$(git rev-parse D) $(git rev-parse HEAD)
+EOF
+       verify_hook_input
+'
+
 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 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 19c72f55bf60c746f72e640e24043b2d83e00fe3..1de83ef98fdcbfd63469e66ba4886c2477b983ff 100755 (executable)
@@ -92,6 +92,15 @@ test_expect_success 'difftool honors --gui' '
        restore_test_defaults
 '
 
+test_expect_success 'difftool --gui works without configured diff.guitool' '
+       git config diff.tool test-tool &&
+
+       diff=$(git difftool --no-prompt --gui branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
 # Specify the diff tool using $GIT_DIFF_TOOL
 test_expect_success 'GIT_DIFF_TOOL variable' '
        git config --unset diff.tool
index 356964e53a1acba1558881865fd99acdee48a17f..d43f37ccafb4ecf6f649a5504d2626f652d48d02 100755 (executable)
@@ -150,20 +150,22 @@ test_expect_success 'setup submodule' '
 
        git checkout -f master &&
        mkdir sub &&
-       cd sub &&
-       git init  &&
-       echo test file > file &&
-       git add file &&
-       git commit -m sub_initial &&
-       cd .. &&
+       (
+               cd sub &&
+               git init  &&
+               echo test file > file &&
+               git add file &&
+               git commit -m sub_initial
+       ) &&
        git submodule add "`pwd`/sub" sub &&
        git commit -m initial &&
        test_tick &&
-       cd sub &&
-       echo more data >> file &&
-       git add file &&
-       git commit -m sub_second &&
-       cd .. &&
+       (
+               cd sub &&
+               echo more data >> file &&
+               git add file &&
+               git commit -m sub_second
+       ) &&
        git add sub &&
        git commit -m second
 
@@ -264,19 +266,20 @@ test_expect_success 'cope with tagger-less tags' '
 
 test_expect_success 'setup for limiting exports by PATH' '
        mkdir limit-by-paths &&
-       cd limit-by-paths &&
-       git init &&
-       echo hi > there &&
-       git add there &&
-       git commit -m "First file" &&
-       echo foo > bar &&
-       git add bar &&
-       git commit -m "Second file" &&
-       git tag -a -m msg mytag &&
-       echo morefoo >> bar &&
-       git add bar &&
-       git commit -m "Change to second file" &&
-       cd ..
+       (
+               cd limit-by-paths &&
+               git init &&
+               echo hi > there &&
+               git add there &&
+               git commit -m "First file" &&
+               echo foo > bar &&
+               git add bar &&
+               git commit -m "Second file" &&
+               git tag -a -m msg mytag &&
+               echo morefoo >> bar &&
+               git add bar &&
+               git commit -m "Change to second file"
+       )
 '
 
 cat > limit-by-paths/expected << EOF
@@ -297,10 +300,11 @@ M 100644 :1 there
 EOF
 
 test_expect_success 'dropping tag of filtered out object' '
+(
        cd limit-by-paths &&
        git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
-       test_cmp output expected &&
-       cd ..
+       test_cmp output expected
+)
 '
 
 cat >> limit-by-paths/expected << EOF
@@ -313,10 +317,11 @@ msg
 EOF
 
 test_expect_success 'rewriting tag of filtered out object' '
+(
        cd limit-by-paths &&
        git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
-       test_cmp output expected &&
-       cd ..
+       test_cmp output expected
+)
 '
 
 cat > limit-by-paths/expected << EOF
@@ -343,13 +348,13 @@ M 100644 :2 there
 EOF
 
 test_expect_failure 'no exact-ref revisions included' '
-       cd limit-by-paths &&
-       git fast-export master~2..master~1 > output &&
-       test_cmp output expected &&
-       cd ..
+       (
+               cd limit-by-paths &&
+               git fast-export master~2..master~1 > output &&
+               test_cmp output expected
+       )
 '
 
-
 test_expect_success 'set-up a few more tags for tag export tests' '
        git checkout -f master &&
        HEAD_TREE=`git show -s --pretty=raw HEAD | grep tree | sed "s/tree //"` &&
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);