Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--.mailmap3
-rw-r--r--Documentation/Makefile8
-rw-r--r--Documentation/RelNotes-1.7.0.4.txt27
-rw-r--r--Documentation/RelNotes-1.7.0.5.txt26
-rw-r--r--Documentation/RelNotes-1.7.0.6.txt13
-rw-r--r--Documentation/RelNotes-1.7.1.txt55
-rw-r--r--Documentation/SubmittingPatches35
-rw-r--r--Documentation/blame-options.txt19
-rw-r--r--Documentation/config.txt18
-rw-r--r--Documentation/diff-options.txt4
-rw-r--r--Documentation/everyday.txt51
-rw-r--r--Documentation/git-branch.txt6
-rw-r--r--Documentation/git-cherry-pick.txt6
-rw-r--r--Documentation/git-fetch.txt8
-rw-r--r--Documentation/git-http-backend.txt2
-rw-r--r--Documentation/git-imap-send.txt10
-rw-r--r--Documentation/git-merge.txt3
-rw-r--r--Documentation/git-push.txt2
-rw-r--r--Documentation/git-rebase.txt23
-rw-r--r--Documentation/git-remote-helpers.txt118
-rw-r--r--Documentation/git-send-email.txt15
-rw-r--r--Documentation/git-show-ref.txt2
-rw-r--r--Documentation/git-status.txt43
-rw-r--r--Documentation/git.txt10
-rw-r--r--Documentation/howto/revert-a-faulty-merge.txt90
-rw-r--r--Documentation/merge-options.txt10
-rw-r--r--Documentation/technical/api-string-list.txt6
-rw-r--r--Documentation/technical/pack-protocol.txt10
-rw-r--r--Documentation/urls.txt59
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile63
-rw-r--r--branch.c2
-rw-r--r--builtin/apply.c5
-rw-r--r--builtin/checkout.c3
-rw-r--r--builtin/clone.c6
-rw-r--r--builtin/commit.c6
-rw-r--r--builtin/fast-export.c2
-rw-r--r--builtin/fetch.c8
-rw-r--r--builtin/fmt-merge-msg.c159
-rw-r--r--builtin/grep.c15
-rw-r--r--builtin/index-pack.c2
-rw-r--r--builtin/log.c54
-rw-r--r--builtin/ls-files.c7
-rw-r--r--builtin/ls-tree.c6
-rw-r--r--builtin/mailinfo.c3
-rw-r--r--builtin/merge-file.c6
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/notes.c530
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/reflog.c2
-rw-r--r--builtin/reset.c3
-rw-r--r--builtin/rev-list.c7
-rw-r--r--builtin/revert.c150
-rw-r--r--builtin/tag.c4
-rw-r--r--cache.h5
-rw-r--r--combine-diff.c17
-rw-r--r--commit.h5
-rw-r--r--compat/bswap.h2
-rw-r--r--compat/mingw.c30
-rw-r--r--compat/mingw.h1
-rw-r--r--compat/vcbuild/include/termios.h1
-rw-r--r--configure.ac20
-rw-r--r--contrib/ciabot/README12
-rwxr-xr-xcontrib/ciabot/ciabot.py222
-rwxr-xr-xcontrib/ciabot/ciabot.sh192
-rwxr-xr-xcontrib/completion/git-completion.bash94
-rwxr-xr-xcontrib/fast-import/import-zips.py2
-rwxr-xr-xcontrib/hg-to-git/hg-to-git.py2
-rw-r--r--contrib/p4import/git-p4import.py2
-rw-r--r--daemon.c11
-rw-r--r--diff.c81
-rw-r--r--git-compat-util.h12
-rwxr-xr-xgit-difftool.perl12
-rwxr-xr-xgit-instaweb.sh10
-rwxr-xr-xgit-rebase--interactive.sh31
-rwxr-xr-xgit-rebase.sh4
-rwxr-xr-xgit-send-email.perl85
-rwxr-xr-xgit-stash.sh8
-rwxr-xr-xgit-submodule.sh2
-rw-r--r--git.spec.in7
-rw-r--r--git_remote_helpers/Makefile6
-rw-r--r--gitk-git/gitk72
-rw-r--r--gitk-git/po/de.po4
-rw-r--r--gitk-git/po/es.po4
-rw-r--r--gitk-git/po/fr.po4
-rw-r--r--gitk-git/po/hu.po4
-rw-r--r--gitk-git/po/it.po4
-rw-r--r--gitk-git/po/ja.po4
-rw-r--r--gitk-git/po/ru.po4
-rw-r--r--gitk-git/po/sv.po4
-rw-r--r--gitweb/INSTALL26
-rw-r--r--gitweb/Makefile89
-rw-r--r--gitweb/README3
-rwxr-xr-xgitweb/gitweb.perl3
-rw-r--r--grep.c18
-rw-r--r--http-backend.c18
-rw-r--r--imap-send.c14
-rw-r--r--ll-merge.c24
-rw-r--r--ll-merge.h2
-rw-r--r--merge-file.c8
-rw-r--r--merge-recursive.c12
-rw-r--r--merge-recursive.h1
-rw-r--r--notes.h2
-rw-r--r--parse-options.c15
-rw-r--r--parse-options.h1
-rw-r--r--pretty.c40
-rw-r--r--refs.c1
-rw-r--r--rerere.c4
-rw-r--r--run-command.c4
-rw-r--r--sha1_file.c6
-rw-r--r--string-list.c13
-rw-r--r--string-list.h3
-rw-r--r--submodule.c33
-rwxr-xr-xt/t0000-basic.sh21
-rwxr-xr-xt/t1010-mktree.sh10
-rwxr-xr-xt/t1304-default-acl.sh23
-rwxr-xr-xt/t3301-notes.sh38
-rwxr-xr-xt/t3404-rebase-interactive.sh45
-rwxr-xr-xt/t3506-cherry-pick-ff.sh98
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh198
-rwxr-xr-xt/t4014-format-patch.sh4
-rwxr-xr-xt/t4017-diff-retval.sh23
-rwxr-xr-xt/t4038-diff-combined.sh8
-rwxr-xr-xt/t4041-diff-submodule.sh15
-rwxr-xr-xt/t5407-post-rewrite-hook.sh16
-rwxr-xr-xt/t5505-remote.sh47
-rwxr-xr-xt/t5601-clone.sh2
-rwxr-xr-xt/t6006-rev-list-format.sh9
-rwxr-xr-xt/t6023-merge-file.sh4
-rwxr-xr-xt/t6200-fmt-merge-msg.sh196
-rwxr-xr-xt/t7012-skip-worktree-writing.sh12
-rwxr-xr-xt/t7201-co.sh69
-rwxr-xr-xt/t7506-status-submodule.sh16
-rwxr-xr-xt/t7800-difftool.sh9
-rwxr-xr-xt/t9350-fast-export.sh71
-rw-r--r--t/test-lib.sh41
-rw-r--r--templates/Makefile17
-rwxr-xr-xtemplates/hooks--commit-msg.sample2
-rwxr-xr-xtemplates/hooks--post-update.sample2
-rwxr-xr-xtemplates/hooks--pre-commit.sample4
-rwxr-xr-xtemplates/hooks--pre-rebase.sample20
-rwxr-xr-xtemplates/hooks--prepare-commit-msg.sample6
-rwxr-xr-xtemplates/hooks--update.sample4
-rw-r--r--templates/info--exclude2
-rw-r--r--xdiff-interface.c11
-rw-r--r--xdiff-interface.h3
-rw-r--r--xdiff/xdiff.h6
-rw-r--r--xdiff/xmerge.c52
149 files changed, 3047 insertions, 1112 deletions
diff --git a/.gitignore b/.gitignore
index 7b3acb7664..dbf1b90c63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -155,7 +155,9 @@
/git-write-tree
/git-core-*/?*
/gitk-git/gitk-wish
+/gitweb/GITWEB-BUILD-OPTIONS
/gitweb/gitweb.cgi
+/gitweb/gitweb.min.*
/test-chmtime
/test-ctype
/test-date
@@ -177,7 +179,7 @@
*.exe
*.[aos]
*.py[co]
-*.o.d
+.depend/
*+
/config.mak
/autom4te.cache
diff --git a/.mailmap b/.mailmap
index 88bd01e16d..a8091eb5df 100644
--- 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/Makefile b/Documentation/Makefile
index 8a8a3954dc..04f69cf64e 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -264,7 +264,9 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
mv $@+ $@
user-manual.xml: user-manual.txt user-manual.conf
- $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book $<
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book -o $@+ $< && \
+ mv $@+ $@
technical/api-index.txt: technical/api-index-skel.txt \
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
@@ -278,7 +280,9 @@ XSLT = docbook.xsl
XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
user-manual.html: user-manual.xml
- $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
+ $(QUIET_XSLTPROC)$(RM) $@+ $@ && \
+ xsltproc $(XSLTOPTS) -o $@+ $(XSLT) $< && \
+ mv $@+ $@
git.info: user-manual.texi
$(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
diff --git a/Documentation/RelNotes-1.7.0.4.txt b/Documentation/RelNotes-1.7.0.4.txt
new file mode 100644
index 0000000000..cf7f60e60d
--- /dev/null
+++ b/Documentation/RelNotes-1.7.0.4.txt
@@ -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.
diff --git a/Documentation/RelNotes-1.7.0.5.txt b/Documentation/RelNotes-1.7.0.5.txt
new file mode 100644
index 0000000000..3149c91b7b
--- /dev/null
+++ b/Documentation/RelNotes-1.7.0.5.txt
@@ -0,0 +1,26 @@
+Git v1.7.0.5 Release Notes
+==========================
+
+Fixes since v1.7.0.4
+--------------------
+
+ * "git daemon" failed to compile on platforms without sockaddr_storage type.
+
+ * Output from "git rev-list --pretty=oneline" was unparsable when a
+ commit did not have any message, which is abnormal but possible in a
+ repository converted from foreign scm.
+
+ * "git stash show <commit-that-is-not-a-stash>" gave an error message
+ that was not so useful. Reworded the message to "<it> is not a
+ stash".
+
+ * Python scripts in contrib/ area now start with "#!/usr/bin/env python"
+ to honor user's PATH.
+
+ * "git imap-send" used to mistake any line that begins with "From " as a
+ message separator in format-patch output.
+
+ * Smart http server backend failed to report an internal server error and
+ infinitely looped instead after output pipe was closed.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.0.6.txt b/Documentation/RelNotes-1.7.0.6.txt
new file mode 100644
index 0000000000..b2852b67d0
--- /dev/null
+++ b/Documentation/RelNotes-1.7.0.6.txt
@@ -0,0 +1,13 @@
+Git v1.7.0.6 Release Notes
+==========================
+
+Fixes since v1.7.0.5
+--------------------
+
+ * "git diff --stat" used "int" to count the size of differences,
+ which could result in overflowing.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+ newer tools in the git toolset.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.1.txt b/Documentation/RelNotes-1.7.1.txt
index 750d40f34a..9d89fedb36 100644
--- a/Documentation/RelNotes-1.7.1.txt
+++ b/Documentation/RelNotes-1.7.1.txt
@@ -1,25 +1,31 @@
-Git v1.7.1 Release Notes (draft)
-================================
+Git v1.7.1 Release Notes
+========================
Updates since v1.7.0
--------------------
+ * Eric Raymond is the maintainer of updated CIAbot scripts, in contrib/.
+
+ * gitk updates.
+
* Some commands (e.g. svn and http interfaces) that interactively ask
- password can be told to use an external program given via GIT_ASKPASS.
+ for a password can be told to use an external program given via
+ GIT_ASKPASS.
- * Color values given to "color.<cmd>.<slot>" configuration can now have
- more than one attributes (e.g. "bold ul").
+ * Conflict markers that lead the common ancestor in diff3-style output
+ now have a label, which hopefully would help third-party tools that
+ expect one.
- * "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.
+ * Comes with an updated bash-completion script.
* "git am" learned "--keep-cr" option to handle inputs that are
- mixture of changes to files with and without CRLF line endings.
+ a 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 describes dirty submodules.
+
* "git for-each-ref" learned %(symref), %(symref:short) and %(flag)
tokens.
@@ -36,11 +42,14 @@ Updates since v1.7.0
* "git grep" learned to paint filename and line-number in colors.
- * "git merge-file" learned to use custom conflict marker size and also use
- the "union merge" behaviour.
+ * "git log -p --first-parent -m" shows one-parent diff for merge
+ commits, instead of showing combined diff.
- * "git notes" command has been rewritten in C and learned quite a
- many commands.
+ * "git merge-file" learned to use custom conflict marker size and also
+ to use the "union merge" behaviour.
+
+ * "git notes" command has been rewritten in C and learned 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,11 +58,18 @@ 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 describes dirty submodules.
+
* "git svn" should work better when interacting with repositories
with CRLF line endings.
* "git imap-send" learned to support CRAM-MD5 authentication.
+ * "gitweb" installation procedure can use "minified" js/css files
+ better.
+
+ * Various documentation updates.
+
Fixes since v1.7.0
------------------
@@ -63,8 +79,11 @@ release, unless otherwise noted.
* "git add frotz/nitfol" did not complain when the entire frotz/ directory
was ignored.
----
-exec >/var/tmp/1
-echo O=$(git describe)
-O=v1.7.0.2-323-g0d0925c
-git shortlog --no-merges ^maint $O..
+ * "git diff --stat" used "int" to count the size of differences,
+ which could result in overflowing.
+
+ * "git rev-list --pretty=oneline" didn't terminate a record with LF for
+ commits without any message.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+ newer tools in the git toolset.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index c686f8646b..abc65de946 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -520,11 +520,9 @@ Gmail
GMail does not appear to have any way to turn off line wrapping in the web
interface, so this will mangle any emails that you send. You can however
use any IMAP email client to connect to the google imap server, and forward
-the emails through that. Just make sure to disable line wrapping in that
-email client. Alternatively, use "git send-email" instead.
+the emails through that.
-Submitting properly formatted patches via Gmail is simple now that
-IMAP support is available. First, edit your ~/.gitconfig to specify your
+To submit using the IMAP interface, first, edit your ~/.gitconfig to specify your
account settings:
[imap]
@@ -538,14 +536,29 @@ account settings:
You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error
that the "Folder doesn't exist".
-Next, ensure that your Gmail settings are correct. In "Settings" the
-"Use Unicode (UTF-8) encoding for outgoing messages" should be checked.
+Once your commits are ready to be sent to the mailing list, run the
+following command to send the patch emails to your Gmail Drafts
+folder.
-Once your commits are ready to send to the mailing list, run the following
-command to send the patch emails to your Gmail Drafts folder.
+ $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
- $ git format-patch -M --stdout origin/master | git imap-send
+Just make sure to disable line wrapping in the email client (GMail web
+interface will line wrap no matter what, so you need to use a real
+IMAP client).
-Go to your Gmail account, open the Drafts folder, find the patch email, fill
-in the To: and CC: fields and send away!
+Alternatively, you can use "git send-email" and send your patches
+through the GMail SMTP server. edit ~/.gitconfig to specify your
+account settings:
+
+[sendemail]
+ smtpencryption = tls
+ smtpserver = smtp.gmail.com
+ smtpuser = user@gmail.com
+ smtppass = p4ssw0rd
+ smtpserverport = 587
+
+Once your commits are ready to be sent to the mailing list, run the
+following commands:
+ $ git format-patch --cover-letter -M origin/master -o outgoing/
+ $ git send-email outgoing/*
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index 4833cac4b9..d8205691c6 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -79,14 +79,15 @@ of lines before or after the line given by <start>.
of the --date option at linkgit:git-log[1].
-M|<num>|::
- Detect moving lines in the file as well. When a commit
- moves a block of lines in a file (e.g. the original file
- has A and then B, and the commit changes it to B and
- then A), the traditional 'blame' algorithm typically blames
- the lines that were moved up (i.e. B) to the parent and
- assigns blame to the lines that were moved down (i.e. A)
- to the child commit. With this option, both groups of lines
- are blamed on the parent.
+ Detect moved or copied lines within a file. When a commit
+ moves or copies a block of lines (e.g. the original file
+ has A and then B, and the commit changes it to B and then
+ A), the traditional 'blame' algorithm notices only half of
+ the movement and typically blames the lines that were moved
+ up (i.e. B) to the parent and assigns blame to the lines that
+ were moved down (i.e. A) to the child commit. With this
+ option, both groups of lines are blamed on the parent by
+ running extra passes of inspection.
+
<num> is optional but it is the lower bound on the number of
alphanumeric characters that git must detect as moving
@@ -94,7 +95,7 @@ within a file for it to associate those lines with the parent
commit.
-C|<num>|::
- In addition to `-M`, detect lines copied from other
+ In addition to `-M`, detect lines moved or copied from other
files that were modified in the same commit. This is
useful when you reorganize your program and move code
around across files. When this option is given twice,
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 06b2f827b4..8f86050b05 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -198,11 +198,11 @@ core.quotepath::
core.autocrlf::
If true, makes git convert `CRLF` at the end of lines in text files to
- `LF` when reading from the filesystem, and convert in reverse when
- writing to the filesystem. The variable can be set to
+ `LF` when reading from the work tree, and convert in reverse when
+ writing to the work tree. The variable can be set to
'input', in which case the conversion happens only while
- reading from the filesystem but files are written out with
- `LF` at the end of lines. A file is considered
+ reading from the work tree but files are written out to the work
+ tree with `LF` at the end of lines. A file is considered
"text" (i.e. be subjected to the autocrlf mechanism) based on
the file's `crlf` attribute, or if `crlf` is unspecified,
based on the file's contents. See linkgit:gitattributes[5].
@@ -914,7 +914,7 @@ format.signoff::
gc.aggressiveWindow::
The window size parameter used in the delta compression
algorithm used by 'git gc --aggressive'. This defaults
- to 10.
+ to 250.
gc.auto::
When there are approximately more than this many loose
@@ -1359,10 +1359,6 @@ notes.rewrite.<command>::
automatically copies your notes from the original to the
rewritten commit. Defaults to `true`, but see
"notes.rewriteRef" below.
-+
-This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
-environment variable, which must be a colon separated list of refs or
-globs.
notes.rewriteMode::
When copying notes during a rewrite (see the
@@ -1382,6 +1378,10 @@ notes.rewriteRef::
+
Does not have a default value; you must configure this variable to
enable note rewriting.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
+environment variable, which must be a colon separated list of refs or
+globs.
pack.window::
The size of the window used by linkgit:git-pack-objects[1] when no
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 60e922e6ef..c9c6c2b1cb 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -94,8 +94,8 @@ Also, when `--raw` or `--numstat` has been given, do not munge
pathnames and use NULs as output field terminators.
endif::git-log[]
ifndef::git-log[]
- When `--raw` or `--numstat` has been given, do not munge
- pathnames and use NULs as output field terminators.
+ When `--raw`, `--numstat`, `--name-only` or `--name-status` has been
+ given, do not munge pathnames and use NULs as output field terminators.
endif::git-log[]
+
Without this option, each pathname output will have TAB, LF, double quotes,
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index 9310b650d3..e0ba8cc075 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -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.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 903a690f10..1940256930 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -63,7 +63,9 @@ way to clean up all obsolete remote-tracking branches.
OPTIONS
-------
-d::
- Delete a branch. The branch must be fully merged in HEAD.
+ Delete a branch. The branch must be fully merged in its
+ upstream branch, or in `HEAD` if no upstream was set with
+ `--track` or `--set-upstream`.
-D::
Delete a branch irrespective of its merged status.
@@ -72,6 +74,8 @@ OPTIONS
Create the branch's reflog. This activates recording of
all changes made to the branch ref, enabling use of date
based sha1 expressions such as "<branchname>@\{yesterday}".
+ Note that in non-bare repositories, reflogs are usually
+ enabled by default by the `core.logallrefupdates` config option.
-f::
--force::
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 78f4714da0..d71607a85d 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -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
------
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 948ea26c5a..400fe7f956 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -8,13 +8,13 @@ git-fetch - Download objects and refs from another repository
SYNOPSIS
--------
-'git fetch' <options> <repository> <refspec>...
+'git fetch' [<options>] [<repository> [<refspec>...]]
-'git fetch' <options> <group>
+'git fetch' [<options>] <group>
-'git fetch' --multiple <options> [<repository> | <group>]...
+'git fetch' --multiple [<options>] [<repository> | <group>]...
-'git fetch' --all <options>
+'git fetch' --all [<options>]
DESCRIPTION
diff --git a/Documentation/git-http-backend.txt b/Documentation/git-http-backend.txt
index 5238820657..277d9e141b 100644
--- a/Documentation/git-http-backend.txt
+++ b/Documentation/git-http-backend.txt
@@ -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.
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 6cafbe2ec1..57aba42e66 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -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.
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 9c9618cead..c2325ef90e 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -9,7 +9,8 @@ git-merge - Join two or more development histories together
SYNOPSIS
--------
[verse]
-'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
+'git merge' [-n] [--stat] [--no-commit] [--squash]
+ [-s <strategy>] [-X <strategy-option>]
[--[no-]rerere-autoupdate] [-m <msg>] <commit>...
'git merge' <msg> HEAD <commit>...
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 59dc8b197e..48570242fb 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream]
- [<repository> <refspec>...]
+ [<repository> [<refspec>...]]
DESCRIPTION
-----------
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 823f2a4638..0d07b1b207 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -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[]
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index 1b5f61aa0b..3a23477ce7 100644
--- a/Documentation/git-remote-helpers.txt
+++ b/Documentation/git-remote-helpers.txt
@@ -3,20 +3,69 @@ git-remote-helpers(1)
NAME
----
-git-remote-helpers - Helper programs for interoperation with remote git
+git-remote-helpers - Helper programs to interact with remote repositories
SYNOPSIS
--------
-'git remote-<transport>' <remote>
+'git remote-<transport>' <repository> [<URL>]
DESCRIPTION
-----------
-These programs are normally not used directly by end users, but are
-invoked by various git programs that interact with remote repositories
-when the repository they would operate on will be accessed using
-transport code not linked into the main git binary. Various particular
-helper programs will behave as documented here.
+Remote helper programs are normally not used directly by end users,
+but they are invoked by git when it needs to interact with remote
+repositories git does not support natively. A given helper will
+implement a subset of the capabilities documented here. When git
+needs to interact with a repository using a remote helper, it spawns
+the helper as an independent process, sends commands to the helper's
+standard input, and expects results from the helper's standard
+output. Because a remote helper runs as an independent process from
+git, there is no need to re-link git to add a new helper, nor any
+need to link the helper with the implementation of git.
+
+Every helper must support the "capabilities" command, which git will
+use to determine what other commands the helper will accept. Other
+commands generally concern facilities like discovering and updating
+remote refs, transporting objects between the object database and
+the remote repository, and updating the local object store.
+
+Helpers supporting the 'fetch' capability can discover refs from the
+remote repository and transfer objects reachable from those refs to
+the local object store. Helpers supporting the 'push' capability can
+transfer local objects to the remote repository and update remote refs.
+
+Git comes with a "curl" family of remote helpers, that handle various
+transport protocols, such as 'git-remote-http', 'git-remote-https',
+'git-remote-ftp' and 'git-remote-ftps'. They implement the capabilities
+'fetch', 'option', and 'push'.
+
+INVOCATION
+----------
+
+Remote helper programs are invoked with one or (optionally) two
+arguments. The first argument specifies a remote repository as in git;
+it is either the name of a configured remote or a URL. The second
+argument specifies a URL; it is usually of the form
+'<transport>://<address>', but any arbitrary string is possible.
+
+When git encounters a URL of the form '<transport>://<address>', where
+'<transport>' is a protocol that it cannot handle natively, it
+automatically invokes 'git remote-<transport>' with the full URL as
+the second argument. If such a URL is encountered directly on the
+command line, the first argument is the same as the second, and if it
+is encountered in a configured remote, the first argument is the name
+of that remote.
+
+A URL of the form '<transport>::<address>' explicitly instructs git to
+invoke 'git remote-<transport>' with '<address>' as the second
+argument. If such a URL is encountered directly on the command line,
+the first argument is '<address>', and if it is encountered in a
+configured remote, the first argument is the name of that remote.
+
+Additionally, when a configured remote has 'remote.<name>.vcs' set to
+'<transport>', git explicitly invokes 'git remote-<transport>' with
+'<name>' as the first argument. If set, the second argument is
+'remote.<name>.url'; otherwise, the second argument is omitted.
COMMANDS
--------
@@ -25,8 +74,8 @@ Commands are given by the caller on the helper's standard input, one per line.
'capabilities'::
Lists the capabilities of the helper, one per line, ending
- with a blank line. Each capability may be preceded with '*'.
- This marks them mandatory for git version using the remote
+ with a blank line. Each capability may be preceded with '*',
+ which marks them mandatory for git version using the remote
helper to understand (unknown mandatory capability is fatal
error).
@@ -35,27 +84,27 @@ Commands are given by the caller on the helper's standard input, one per line.
[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
a symref, or "?" to indicate that the helper could not get the
value of the ref. A space-separated list of attributes follows
- the name; unrecognized attributes are ignored. After the
- complete list, outputs a blank line.
+ the name; unrecognized attributes are ignored. The list ends
+ with a blank line.
+
If 'push' is supported this may be called as 'list for-push'
to obtain the current refs prior to sending one or more 'push'
commands to the helper.
'option' <name> <value>::
- Set the transport helper option <name> to <value>. Outputs a
+ Sets the transport helper option <name> to <value>. Outputs a
single line containing one of 'ok' (option successfully set),
'unsupported' (option not recognized) or 'error <msg>'
- (option <name> is supported but <value> is not correct
+ (option <name> is supported but <value> is not valid
for it). Options should be set before other commands,
- and may how those commands behave.
+ and may influence the behavior of those commands.
+
Supported if the helper has the "option" capability.
'fetch' <sha1> <name>::
Fetches the given object, writing the necessary objects
to the database. Fetch commands are sent in a batch, one
- per line, and the batch is terminated with a blank line.
+ per line, terminated with a blank line.
Outputs a single blank line when all fetch commands in the
same batch are complete. Only objects which were reported
in the ref list with a sha1 may be fetched this way.
@@ -67,7 +116,7 @@ suitably updated.
Supported if the helper has the "fetch" capability.
'push' +<src>:<dst>::
- Pushes the given <src> commit or branch locally to the
+ Pushes the given local <src> commit or branch to the
remote branch described by <dst>. A batch sequence of
one or more push commands is terminated with a blank line.
+
@@ -91,6 +140,9 @@ Supported if the helper has the "push" capability.
by applying the refspecs from the "refspec" capability to the
name of the ref.
+
+Especially useful for interoperability with a foreign versioning
+system.
++
Supported if the helper has the "import" capability.
'connect' <service>::
@@ -119,16 +171,11 @@ CAPABILITIES
------------
'fetch'::
- This helper supports the 'fetch' command.
-
'option'::
- This helper supports the option command.
-
'push'::
- This helper supports the 'push' command.
-
'import'::
- This helper supports the 'import' command.
+'connect'::
+ This helper supports the corresponding command with the same name.
'refspec' 'spec'::
When using the import command, expect the source ref to have
@@ -140,9 +187,6 @@ CAPABILITIES
all, it must cover all refs reported by the list command; if
it is not used, it is effectively "*:*"
-'connect'::
- This helper supports the 'connect' command.
-
REF LIST ATTRIBUTES
-------------------
@@ -158,19 +202,19 @@ REF LIST ATTRIBUTES
OPTIONS
-------
'option verbosity' <N>::
- Change the level of messages displayed by the helper.
- When N is 0 the end-user has asked the process to be
- quiet, and the helper should produce only error output.
- N of 1 is the default level of verbosity, higher values
+ Changes the verbosity of messages displayed by the helper.
+ A value of 0 for N means that processes operate
+ quietly, and the helper produces only error output.
+ 1 is the default level of verbosity, and higher values
of N correspond to the number of -v flags passed on the
command line.
'option progress' \{'true'|'false'\}::
- Enable (or disable) progress messages displayed by the
+ Enables (or disables) progress messages displayed by the
transport helper during a command.
'option depth' <depth>::
- Deepen the history of a shallow repository.
+ Deepens the history of a shallow repository.
'option followtags' \{'true'|'false'\}::
If enabled the helper should automatically fetch annotated
@@ -186,11 +230,15 @@ OPTIONS
helpers this only applies to the 'push', if supported.
'option servpath <c-style-quoted-path>'::
- Set service path (--upload-pack, --receive-pack etc.) for
- next connect. Remote helper MAY support this option. Remote
- helper MUST NOT rely on this option being set before
+ Sets service path (--upload-pack, --receive-pack etc.) for
+ next connect. Remote helper may support this option, but
+ must not rely on this option being set before
connect request occurs.
+SEE ALSO
+--------
+linkgit:git-remote[1]
+
Documentation
-------------
Documentation by Daniel Barkalow and Ilari Liusvaara
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index ced35b2f53..3dfdc7cca6 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -300,6 +300,21 @@ sendemail.confirm::
in the previous section for the meaning of these values.
+Use gmail as the smtp server
+----------------------------
+
+Add the following section to the config file:
+
+ [sendemail]
+ smtpencryption = tls
+ smtpserver = smtp.gmail.com
+ smtpuser = yourname@gmail.com
+ smtpserverport = 587
+
+Note: the following perl modules are required
+ Net::SMTP::SSL, MIME::Base64 and Authen::SASL
+
+
Author
------
Written by Ryan Anderson <ryan@michonline.com>
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index df17d49b87..3f9d9c6db3 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -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
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 1cab91b534..2d4bbfcaf4 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -72,21 +72,37 @@ In short-format, the status of each path is shown as
where `PATH1` is the path in the `HEAD`, and ` -> PATH2` part is
shown only when `PATH1` corresponds to a different path in the
-index/worktree (i.e. renamed).
-
-For unmerged entries, `X` shows the status of stage #2 (i.e. ours) and `Y`
-shows the status of stage #3 (i.e. theirs).
-
-For entries that do not have conflicts, `X` shows the status of the index,
-and `Y` shows the status of the work tree. For untracked paths, `XY` are
-`??`.
+index/worktree (i.e. the file is renamed). The 'XY' is a two-letter
+status code.
+
+The fields (including the `->`) are separated from each other by a
+single space. If a filename contains whitespace or other nonprintable
+characters, that field will be quoted in the manner of a C string
+literal: surrounded by ASCII double quote (34) characters, and with
+interior special characters backslash-escaped.
+
+For paths with merge conflicts, `X` and 'Y' show the modification
+states of each side of the merge. For paths that do not have merge
+conflicts, `X` shows the status of the index, and `Y` shows the status
+of the work tree. For untracked paths, `XY` are `??`. Other status
+codes can be interpreted as follows:
+
+* ' ' = unmodified
+* 'M' = modified
+* 'A' = added
+* 'D' = deleted
+* 'R' = renamed
+* 'C' = copied
+* 'U' = updated but unmerged
+
+Ignored files are not listed.
X Y Meaning
-------------------------------------------------
[MD] not updated
M [ MD] updated in index
A [ MD] added to index
- D [ MD] deleted from index
+ D [ M] deleted from index
R [ MD] renamed in index
C [ MD] copied in index
[MARC] index and work tree matches
@@ -104,6 +120,15 @@ and `Y` shows the status of the work tree. For untracked paths, `XY` are
? ? untracked
-------------------------------------------------
+There is an alternate -z format recommended for machine parsing. In
+that format, the status field is the same, but some other things
+change. First, the '->' is omitted from rename entries and the field
+order is reversed (e.g 'from -> to' becomes 'to from'). Second, a NUL
+(ASCII 0) follows each filename, replacing space as a field separator
+and the terminating newline (but a space still separates the status
+field from the first filename). Third, filenames containing special
+characters are not specially formatted; no quoting or
+backslash-escaping is performed.
CONFIGURATION
-------------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 4e00b315ff..c4024d0edd 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,17 @@ 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.1/git.html[documentation for release 1.7.1]
* release notes for
+ link:RelNotes-1.7.1.txt[1.7.1].
+
+* link:v1.7.0.6/git.html[documentation for release 1.7.0.6]
+
+* release notes for
+ link:RelNotes-1.7.0.6.txt[1.7.0.6],
+ link:RelNotes-1.7.0.5.txt[1.7.0.5],
+ 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],
diff --git a/Documentation/howto/revert-a-faulty-merge.txt b/Documentation/howto/revert-a-faulty-merge.txt
index 3b4a390005..ff5c0bc27a 100644
--- a/Documentation/howto/revert-a-faulty-merge.txt
+++ b/Documentation/howto/revert-a-faulty-merge.txt
@@ -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
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 37ce9a17fc..722d704ff2 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -62,6 +62,11 @@ option can be used to override --squash.
is used instead ('git merge-recursive' when merging a single
head, 'git merge-octopus' otherwise).
+-X <option>::
+--strategy-option=<option>::
+ Pass merge strategy specific option through to the merge
+ strategy.
+
--summary::
--no-summary::
Synonyms to --stat and --no-stat; these are deprecated and will be
@@ -76,8 +81,3 @@ ifndef::git-pull[]
--verbose::
Be verbose.
endif::git-pull[]
-
--X <option>::
---strategy-option=<option>::
- Pass merge strategy specific option through to the merge
- strategy.
diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt
index 293bb15d20..6d8c24bb1e 100644
--- a/Documentation/technical/api-string-list.txt
+++ b/Documentation/technical/api-string-list.txt
@@ -104,8 +104,12 @@ write `string_list_insert(...)->util = ...;`.
`unsorted_string_list_has_string`::
It's like `string_list_has_string()` but for unsorted lists.
+
+`unsorted_string_list_lookup`::
+
+ It's like `string_list_lookup()` but for unsorted lists.
+
-This function needs to look through all items, as opposed to its
+The above two functions need to look through all items, as opposed to their
counterpart for sorted lists, which performs a binary search.
Data structures
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index 9a5cdafa9c..369f91d3b9 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -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
----
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index 459a394dc0..1dcd1e7f1e 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -1,44 +1,57 @@
GIT URLS[[URLS]]
----------------
-One of the following notations can be used
-to name the remote repository:
+In general, URLs contain information about the transport protocol, the
+address of the remote server, and the path to the repository.
+Depending on the transport protocol, some of this information may be
+absent.
+
+Git natively supports ssh, git, http, https, ftp, ftps, and rsync
+protocols. The following syntaxes may be used with them:
-- rsync://host.xz/path/to/repo.git/
-- http://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- https://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- git://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- git://host.xz{startsb}:port{endsb}/~user/path/to/repo.git/
- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/
-- ssh://{startsb}user@{endsb}host.xz/path/to/repo.git/
-- ssh://{startsb}user@{endsb}host.xz/~user/path/to/repo.git/
-- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git
+- git://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- http{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- ftp{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- rsync://host.xz/path/to/repo.git/
-SSH is the default transport protocol over the network. You can
-optionally specify which user to log-in as, and an alternate,
-scp-like syntax is also supported. Both syntaxes support
-username expansion, as does the native git protocol, but
-only the former supports port specification. The following
-three are identical to the last three above, respectively:
+An alternative scp-like syntax may also be used with the ssh protocol:
-- {startsb}user@{endsb}host.xz:/path/to/repo.git/
-- {startsb}user@{endsb}host.xz:~user/path/to/repo.git/
-- {startsb}user@{endsb}host.xz:path/to/repo.git
+- {startsb}user@{endsb}host.xz:path/to/repo.git/
-To sync with a local directory, you can use:
+The ssh and git protocols additionally support ~username expansion:
+
+- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
+- git://host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
+- {startsb}user@{endsb}host.xz:/~{startsb}user{endsb}/path/to/repo.git/
+
+For local respositories, also supported by git natively, the following
+syntaxes may be used:
- /path/to/repo.git/
- file:///path/to/repo.git/
ifndef::git-clone[]
-They are mostly equivalent, except when cloning. See
-linkgit:git-clone[1] for details.
+These two syntaxes are mostly equivalent, except when cloning, when
+the former implies --local option. See linkgit:git-clone[1] for
+details.
endif::git-clone[]
ifdef::git-clone[]
-They are equivalent, except the former implies --local option.
+These two syntaxes are mostly equivalent, except the former implies
+--local option.
endif::git-clone[]
+When git doesn't know how to handle a certain transport protocol, it
+attempts to use the 'remote-<transport>' remote helper, if one
+exists. To explicitly request a remote helper, the following syntax
+may be used:
+
+- <transport>::<address>
+
+where <address> may be a path, a server and path, or an arbitrary
+URL-like string recognized by the specific remote helper being
+invoked. See linkgit:git-remote-helpers[1] for details.
If there are a large number of similarly-named remote repositories and
you want to use a different format for them (such that the URLs you
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 076c18ecc3..0ad39484ec 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.0.3
+DEF_VER=v1.7.1
LF='
'
diff --git a/Makefile b/Makefile
index 3a6c6ea525..eb1d1623c2 100644
--- 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.
@@ -203,6 +203,9 @@ all::
# Define JSMIN to point to JavaScript minifier that functions as
# a filter to have gitweb.js minified.
#
+# Define CSSMIN to point to a CSS minifier in order to generate a minified
+# version of gitweb.css
+#
# Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
# you want to use something different. The value will be interpreted by the
# shell at runtime when it is used.
@@ -279,9 +282,6 @@ lib = lib
# DESTDIR=
pathsep = :
-# JavaScript minifier invocation that can function as filter
-JSMIN =
-
export prefix bindir sharedir sysconfdir
CC = gcc
@@ -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:
@$$(:)
@@ -1558,18 +1561,29 @@ gitweb:
$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
ifdef JSMIN
-OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.min.js
-gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
+GITWEB_PROGRAMS += gitweb/gitweb.min.js
+GITWEB_JS = gitweb/gitweb.min.js
else
-OTHER_PROGRAMS += gitweb/gitweb.cgi
-gitweb/gitweb.cgi: gitweb/gitweb.perl
+GITWEB_JS = gitweb/gitweb.js
endif
+ifdef CSSMIN
+GITWEB_PROGRAMS += gitweb/gitweb.min.css
+GITWEB_CSS = gitweb/gitweb.min.css
+else
+GITWEB_CSS = gitweb/gitweb.css
+endif
+OTHER_PROGRAMS += gitweb/gitweb.cgi $(GITWEB_PROGRAMS)
+gitweb/gitweb.cgi: gitweb/gitweb.perl $(GITWEB_PROGRAMS)
$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
ifdef JSMIN
gitweb/gitweb.min.js: gitweb/gitweb.js
$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
endif # JSMIN
+ifdef CSSMIN
+gitweb/gitweb.min.css: gitweb/gitweb.css
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+endif # CSSMIN
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
@@ -1579,11 +1593,13 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
-e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \
-e '/@@GITWEB_CGI@@/d' \
- -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
+ -e '/@@GITWEB_CSS@@/r $(GITWEB_CSS)' \
-e '/@@GITWEB_CSS@@/d' \
- -e '/@@GITWEB_JS@@/r gitweb/gitweb.js' \
+ -e '/@@GITWEB_JS@@/r $(GITWEB_JS)' \
-e '/@@GITWEB_JS@@/d' \
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
+ -e 's|@@GITWEB_CSS_NAME@@|$(GITWEB_CSS)|' \
+ -e 's|@@GITWEB_JS_NAME@@|$(GITWEB_JS)|' \
$@.sh > $@+ && \
chmod +x $@+ && \
mv $@+ $@
@@ -1609,9 +1625,8 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
-e '}' \
-e 's|^import sys.*|&; \\\
import os; \\\
- sys.path[0] = os.environ.has_key("GITPYTHONLIB") and \\\
- os.environ["GITPYTHONLIB"] or \\\
- "@@INSTLIBDIR@@"|' \
+ sys.path.insert(0, os.getenv("GITPYTHONLIB",\
+ "@@INSTLIBDIR@@"));|' \
-e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
$@.py >$@+ && \
chmod +x $@+ && \
@@ -2083,7 +2098,7 @@ clean:
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
$(MAKE) -C Documentation/ clean
ifndef NO_PERL
- $(RM) gitweb/gitweb.cgi
+ $(MAKE) -C gitweb clean
$(MAKE) -C perl clean
endif
ifndef NO_PYTHON
diff --git a/branch.c b/branch.c
index 9e1f63ed8d..2ab42aaf4d 100644
--- a/branch.c
+++ b/branch.c
@@ -198,7 +198,7 @@ void create_branch(const char *head,
log_all_ref_updates = 1;
if (forcing)
- snprintf(msg, sizeof msg, "branch: Reset from %s",
+ snprintf(msg, sizeof msg, "branch: Reset to %s",
start_name);
else if (!dont_change_ref)
snprintf(msg, sizeof msg, "branch: Created from %s",
diff --git a/builtin/apply.c b/builtin/apply.c
index 65a594c985..660cf92538 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -2824,11 +2824,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
if (stat_ret < 0) {
struct checkout costate;
/* checkout */
+ memset(&costate, 0, sizeof(costate));
costate.base_dir = "";
- costate.base_dir_len = 0;
- costate.force = 0;
- costate.quiet = 0;
- costate.not_new = 0;
costate.refresh_cache = 1;
if (checkout_entry(*ce, &costate, NULL) ||
lstat(old_name, st))
diff --git a/builtin/checkout.c b/builtin/checkout.c
index acefaaf41a..88b1f43e05 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -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,
diff --git a/builtin/clone.c b/builtin/clone.c
index 05f8fb4771..0bedde41f0 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -302,6 +302,8 @@ static const struct ref *clone_local(const char *src_repo,
transport = transport_get(remote, src_repo);
ret = transport_get_remote_refs(transport);
transport_disconnect(transport);
+ if (0 <= option_verbosity)
+ printf("done.\n");
return ret;
}
@@ -461,7 +463,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die("could not create leading directories of '%s'", git_dir);
set_git_dir(make_absolute_path(git_dir));
- init_db(option_template, (option_verbosity < 0) ? INIT_DB_QUIET : 0);
+ if (0 <= option_verbosity)
+ printf("Cloning into %s...\n", get_git_dir());
+ init_db(option_template, INIT_DB_QUIET);
/*
* At this point, the config exists, so we do not need the
diff --git a/builtin/commit.c b/builtin/commit.c
index 8dd104ee0b..c5ab683d5b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -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) {
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b0a4029c94..c6dd71a7bc 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -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) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 957be9f926..8470850415 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -14,10 +14,10 @@
#include "transport.h"
static const char * const builtin_fetch_usage[] = {
- "git fetch [options] [<repository> <refspec>...]",
- "git fetch [options] <group>",
- "git fetch --multiple [options] [<repository> | <group>]...",
- "git fetch --all [options]",
+ "git fetch [<options>] [<repository> [<refspec>...]]",
+ "git fetch [<options>] <group>",
+ "git fetch --multiple [<options>] [<repository> | <group>]...",
+ "git fetch --all [<options>]",
NULL
};
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 9d524000b5..379a03131f 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -4,6 +4,7 @@
#include "diff.h"
#include "revision.h"
#include "tag.h"
+#include "string-list.h"
static const char * const fmt_merge_msg_usage[] = {
"git fmt-merge-msg [--log|--no-log] [--file <file>]",
@@ -24,58 +25,21 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
return 0;
}
-struct list {
- char **list;
- void **payload;
- unsigned nr, alloc;
+struct src_data {
+ struct string_list branch, tag, r_branch, generic;
+ int head_status;
};
-static void append_to_list(struct list *list, char *value, void *payload)
-{
- if (list->nr == list->alloc) {
- list->alloc += 32;
- list->list = xrealloc(list->list, sizeof(char *) * list->alloc);
- list->payload = xrealloc(list->payload,
- sizeof(char *) * list->alloc);
- }
- list->payload[list->nr] = payload;
- list->list[list->nr++] = value;
-}
-
-static int find_in_list(struct list *list, char *value)
-{
- int i;
-
- for (i = 0; i < list->nr; i++)
- if (!strcmp(list->list[i], value))
- return i;
-
- return -1;
-}
-
-static void free_list(struct list *list)
+void init_src_data(struct src_data *data)
{
- int i;
-
- if (list->alloc == 0)
- return;
-
- for (i = 0; i < list->nr; i++) {
- free(list->list[i]);
- free(list->payload[i]);
- }
- free(list->list);
- free(list->payload);
- list->nr = list->alloc = 0;
+ data->branch.strdup_strings = 1;
+ data->tag.strdup_strings = 1;
+ data->r_branch.strdup_strings = 1;
+ data->generic.strdup_strings = 1;
}
-struct src_data {
- struct list branch, tag, r_branch, generic;
- int head_status;
-};
-
-static struct list srcs = { NULL, NULL, 0, 0};
-static struct list origins = { NULL, NULL, 0, 0};
+static struct string_list srcs = { NULL, 0, 0, 1 };
+static struct string_list origins = { NULL, 0, 0, 1 };
static int handle_line(char *line)
{
@@ -83,6 +47,7 @@ static int handle_line(char *line)
unsigned char *sha1;
char *src, *origin;
struct src_data *src_data;
+ struct string_list_item *item;
int pulling_head = 0;
if (len < 43 || line[40] != '\t')
@@ -115,64 +80,62 @@ static int handle_line(char *line)
pulling_head = 1;
}
- i = find_in_list(&srcs, src);
- if (i < 0) {
- i = srcs.nr;
- append_to_list(&srcs, xstrdup(src),
- xcalloc(1, sizeof(struct src_data)));
+ item = unsorted_string_list_lookup(&srcs, src);
+ if (!item) {
+ item = string_list_append(src, &srcs);
+ item->util = xcalloc(1, sizeof(struct src_data));
+ init_src_data(item->util);
}
- src_data = srcs.payload[i];
+ src_data = item->util;
if (pulling_head) {
- origin = xstrdup(src);
+ origin = src;
src_data->head_status |= 1;
} else if (!prefixcmp(line, "branch ")) {
- origin = xstrdup(line + 7);
- append_to_list(&src_data->branch, origin, NULL);
+ origin = line + 7;
+ string_list_append(origin, &src_data->branch);
src_data->head_status |= 2;
} else if (!prefixcmp(line, "tag ")) {
origin = line;
- append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
+ string_list_append(origin + 4, &src_data->tag);
src_data->head_status |= 2;
} else if (!prefixcmp(line, "remote branch ")) {
- origin = xstrdup(line + 14);
- append_to_list(&src_data->r_branch, origin, NULL);
+ origin = line + 14;
+ string_list_append(origin, &src_data->r_branch);
src_data->head_status |= 2;
} else {
- origin = xstrdup(src);
- append_to_list(&src_data->generic, xstrdup(line), NULL);
+ origin = src;
+ string_list_append(line, &src_data->generic);
src_data->head_status |= 2;
}
if (!strcmp(".", src) || !strcmp(src, origin)) {
int len = strlen(origin);
- if (origin[0] == '\'' && origin[len - 1] == '\'') {
+ if (origin[0] == '\'' && origin[len - 1] == '\'')
origin = xmemdupz(origin + 1, len - 2);
- } else {
- origin = xstrdup(origin);
- }
} else {
char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
sprintf(new_origin, "%s of %s", origin, src);
origin = new_origin;
}
- append_to_list(&origins, origin, sha1);
+ string_list_append(origin, &origins)->util = sha1;
return 0;
}
static void print_joined(const char *singular, const char *plural,
- struct list *list, struct strbuf *out)
+ struct string_list *list, struct strbuf *out)
{
if (list->nr == 0)
return;
if (list->nr == 1) {
- strbuf_addf(out, "%s%s", singular, list->list[0]);
+ strbuf_addf(out, "%s%s", singular, list->items[0].string);
} else {
int i;
strbuf_addstr(out, plural);
for (i = 0; i < list->nr - 1; i++)
- strbuf_addf(out, "%s%s", i > 0 ? ", " : "", list->list[i]);
- strbuf_addf(out, " and %s", list->list[list->nr - 1]);
+ strbuf_addf(out, "%s%s", i > 0 ? ", " : "",
+ list->items[i].string);
+ strbuf_addf(out, " and %s", list->items[list->nr - 1].string);
}
}
@@ -183,8 +146,9 @@ static void shortlog(const char *name, unsigned char *sha1,
int i, count = 0;
struct commit *commit;
struct object *branch;
- struct list subjects = { NULL, NULL, 0, 0 };
+ struct string_list subjects = { NULL, 0, 0, 1 };
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
+ struct strbuf sb = STRBUF_INIT;
branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
if (!branch || branch->type != OBJ_COMMIT)
@@ -198,7 +162,7 @@ static void shortlog(const char *name, unsigned char *sha1,
if (prepare_revision_walk(rev))
die("revision walk setup failed");
while ((commit = get_revision(rev)) != NULL) {
- char *oneline, *bol, *eol;
+ struct pretty_print_context ctx = {0};
/* ignore merges */
if (commit->parents && commit->parents->next)
@@ -208,30 +172,14 @@ static void shortlog(const char *name, unsigned char *sha1,
if (subjects.nr > limit)
continue;
- bol = strstr(commit->buffer, "\n\n");
- if (bol) {
- unsigned char c;
- do {
- c = *++bol;
- } while (isspace(c));
- if (!c)
- bol = NULL;
- }
-
- if (!bol) {
- append_to_list(&subjects, xstrdup(sha1_to_hex(
- commit->object.sha1)),
- NULL);
- continue;
- }
+ format_commit_message(commit, "%s", &sb, &ctx);
+ strbuf_ltrim(&sb);
- eol = strchr(bol, '\n');
- if (eol) {
- oneline = xmemdupz(bol, eol - bol);
- } else {
- oneline = xstrdup(bol);
- }
- append_to_list(&subjects, oneline, NULL);
+ if (!sb.len)
+ string_list_append(sha1_to_hex(commit->object.sha1),
+ &subjects);
+ else
+ string_list_append(strbuf_detach(&sb, NULL), &subjects);
}
if (count > limit)
@@ -243,7 +191,7 @@ static void shortlog(const char *name, unsigned char *sha1,
if (i >= limit)
strbuf_addf(out, " ...\n");
else
- strbuf_addf(out, " %s\n", subjects.list[i]);
+ strbuf_addf(out, " %s\n", subjects.items[i].string);
clear_commit_marks((struct commit *)branch, flags);
clear_commit_marks(head, flags);
@@ -251,7 +199,7 @@ static void shortlog(const char *name, unsigned char *sha1,
rev->commits = NULL;
rev->pending.nr = 0;
- free_list(&subjects);
+ string_list_clear(&subjects, 0);
}
int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
@@ -281,16 +229,19 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
die ("Error in line %d: %.*s", i, len, p);
}
+ if (!srcs.nr)
+ return 0;
+
strbuf_addstr(out, "Merge ");
for (i = 0; i < srcs.nr; i++) {
- struct src_data *src_data = srcs.payload[i];
+ struct src_data *src_data = srcs.items[i].util;
const char *subsep = "";
strbuf_addstr(out, sep);
sep = "; ";
if (src_data->head_status == 1) {
- strbuf_addstr(out, srcs.list[i]);
+ strbuf_addstr(out, srcs.items[i].string);
continue;
}
if (src_data->head_status == 3) {
@@ -319,8 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
print_joined("commit ", "commits ", &src_data->generic,
out);
}
- if (strcmp(".", srcs.list[i]))
- strbuf_addf(out, " of %s", srcs.list[i]);
+ if (strcmp(".", srcs.items[i].string))
+ strbuf_addf(out, " of %s", srcs.items[i].string);
}
if (!strcmp("master", current_branch))
@@ -339,7 +290,7 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
rev.limited = 1;
for (i = 0; i < origins.nr; i++)
- shortlog(origins.list[i], origins.payload[i],
+ shortlog(origins.items[i].string, origins.items[i].util,
head, &rev, limit, out);
}
return 0;
@@ -350,7 +301,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
const char *inpath = NULL;
struct option options[] = {
OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
- OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
+ { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL,
+ "alias for --log (deprecated)",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_FILENAME('F', "file", &inpath, "file to read from"),
OPT_END()
};
diff --git a/builtin/grep.c b/builtin/grep.c
index 9d30ddb28d..8e928e2170 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -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
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index b4cf8c53e0..03d0cd2f47 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -11,7 +11,7 @@
#include "exec_cmd.h"
static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git index-pack [-v] [-o <index-file>] [{ --keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
struct object_entry
{
diff --git a/builtin/log.c b/builtin/log.c
index a8dd8c989c..6208703c06 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -36,6 +36,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
{
int i;
int decoration_style = 0;
+ struct userformat_want w;
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
@@ -58,7 +59,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
usage(builtin_log_usage);
argc = setup_revisions(argc, argv, rev, opt);
- if (!rev->show_notes_given && !rev->pretty_given)
+ memset(&w, 0, sizeof(w));
+ userformat_find_requirements(NULL, &w);
+
+ if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
rev->show_notes = 1;
if (rev->show_notes)
init_display_notes(&rev->notes_opt);
@@ -1157,8 +1161,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 +1307,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 +1322,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 +1350,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 +1403,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;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index b065061392..c0fbcdcf4f 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -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);
}
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 4484185afc..dc86b0d9a9 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -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);
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index ce2ef6bede..4a9729b9b3 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -746,7 +746,8 @@ static int is_scissors_line(const struct strbuf *line)
continue;
}
if (i + 1 < len &&
- (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) {
+ (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) ||
+ !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) {
in_perforation = 1;
perforation += 2;
scissors += 2;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 69cc683332..610849a653 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -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);
diff --git a/builtin/merge.c b/builtin/merge.c
index 3aaec7bed7..c043066845 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -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;
diff --git a/builtin/notes.c b/builtin/notes.c
index 4543d11311..52b72fca68 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -19,13 +19,54 @@
#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;
+}
diff --git a/builtin/push.c b/builtin/push.c
index 62957ededd..f4358b9d23 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const push_usage[] = {
- "git push [<options>] [<repository> <refspec>...]",
+ "git push [<options>] [<repository> [<refspec>...]]",
NULL,
};
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 64e45bd813..bd7880dc04 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -13,7 +13,7 @@
*/
static const char reflog_expire_usage[] =
-"git reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
static const char reflog_delete_usage[] =
"git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
diff --git a/builtin/reset.c b/builtin/reset.c
index 2c3a69adc6..1283068fd2 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -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
};
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 5679170e82..51ceb19d88 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -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);
diff --git a/builtin/revert.c b/builtin/revert.c
index eff52687a8..7d68ef714e 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -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,69 @@ 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";
+
+ out->reencoded_message = NULL;
+ out->message = raw_message;
+ if (strcmp(encoding, git_commit_encoding))
+ out->reencoded_message = reencode_string(raw_message,
+ git_commit_encoding, encoding);
+ if (out->reencoded_message)
+ 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 +294,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 +326,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 +356,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 +384,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 +402,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 +425,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 +439,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 +505,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/builtin/tag.c b/builtin/tag.c
index 4ef1c4f508..d311491e49 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -147,11 +147,11 @@ static int delete_tag(const char *name, const char *ref,
static int verify_tag(const char *name, const char *ref,
const unsigned char *sha1)
{
- const char *argv_verify_tag[] = {"git-verify-tag",
+ const char *argv_verify_tag[] = {"verify-tag",
"-v", "SHA1_HEX", NULL};
argv_verify_tag[2] = sha1_to_hex(sha1);
- if (run_command_v_opt(argv_verify_tag, 0))
+ if (run_command_v_opt(argv_verify_tag, RUN_GIT_CMD))
return error("could not verify the tag '%s'", name);
return 0;
}
diff --git a/cache.h b/cache.h
index 2928107bb1..5eb0573bcc 100644
--- a/cache.h
+++ b/cache.h
@@ -701,7 +701,7 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *
return read_sha1_file_repl(sha1, type, size, NULL);
}
extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
+extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
@@ -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 */
diff --git a/combine-diff.c b/combine-diff.c
index 61626912e3..7557136c82 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -204,18 +204,17 @@ static void consume_line(void *state_, char *line, unsigned long len)
static void combine_diff(const unsigned char *parent, unsigned int mode,
mmfile_t *result_file,
struct sline *sline, unsigned int cnt, int n,
- int num_parent)
+ int num_parent, int result_deleted)
{
unsigned int p_lno, lno;
unsigned long nmask = (1UL << n);
xpparam_t xpp;
xdemitconf_t xecfg;
mmfile_t parent_file;
- xdemitcb_t ecb;
struct combine_diff_state state;
unsigned long sz;
- if (!cnt)
+ if (result_deleted)
return; /* result deleted */
parent_file.ptr = grab_blob(parent, mode, &sz);
@@ -231,7 +230,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
state.n = n;
xdi_diff_outf(&parent_file, result_file, consume_line, &state,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
free(parent_file.ptr);
/* Assign line numbers for this parent.
@@ -517,7 +516,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)
}
static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
- int use_color)
+ int use_color, int result_deleted)
{
unsigned long mark = (1UL<<num_parent);
unsigned long no_pre_delete = (2UL<<num_parent);
@@ -530,7 +529,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
const char *c_plain = diff_get_color(use_color, DIFF_PLAIN);
const char *c_reset = diff_get_color(use_color, DIFF_RESET);
- if (!cnt)
+ if (result_deleted)
return; /* result deleted */
while (1) {
@@ -687,6 +686,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
{
struct diff_options *opt = &rev->diffopt;
unsigned long result_size, cnt, lno;
+ int result_deleted = 0;
char *result, *cp;
struct sline *sline; /* survived lines */
int mode_differs = 0;
@@ -767,6 +767,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
else {
deleted_file:
+ result_deleted = 1;
result_size = 0;
elem->mode = 0;
result = xcalloc(1, 1);
@@ -823,7 +824,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
combine_diff(elem->parent[i].sha1,
elem->parent[i].mode,
&result_file, sline,
- cnt, i, num_parent);
+ cnt, i, num_parent, result_deleted);
if (elem->parent[i].mode != elem->mode)
mode_differs = 1;
}
@@ -889,7 +890,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
dump_quoted_path("+++ ", b_prefix, elem->path,
c_meta, c_reset);
dump_sline(sline, cnt, num_parent,
- DIFF_OPT_TST(opt, COLOR_DIFF));
+ DIFF_OPT_TST(opt, COLOR_DIFF), result_deleted);
}
free(result);
diff --git a/commit.h b/commit.h
index 3cf5166581..26ec8c0d1c 100644
--- a/commit.h
+++ b/commit.h
@@ -74,11 +74,16 @@ struct pretty_print_context
struct reflog_walk_info *reflog_info;
};
+struct userformat_want {
+ unsigned notes:1;
+};
+
extern int has_non_ascii(const char *text);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
extern char *reencode_commit_message(const struct commit *commit,
const char **encoding_p);
extern void get_commit_format(const char *arg, struct rev_info *);
+extern void userformat_find_requirements(const char *fmt, struct userformat_want *w);
extern void format_commit_message(const struct commit *commit,
const char *format, struct strbuf *sb,
const struct pretty_print_context *context);
diff --git a/compat/bswap.h b/compat/bswap.h
index f3b8c44181..54756dbb05 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -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) ({ \
diff --git a/compat/mingw.c b/compat/mingw.c
index c5bfb39b39..f90a114b02 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -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;
}
@@ -634,6 +650,7 @@ static int env_compare(const void *a, const void *b)
}
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+ const char *dir,
int prepend_cmd, int fhin, int fhout, int fherr)
{
STARTUPINFO si;
@@ -713,7 +730,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
memset(&pi, 0, sizeof(pi));
ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
- env ? envblk.buf : NULL, NULL, &si, &pi);
+ env ? envblk.buf : NULL, dir, &si, &pi);
if (env)
strbuf_release(&envblk);
@@ -730,10 +747,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
int prepend_cmd)
{
- return mingw_spawnve_fd(cmd, argv, env, prepend_cmd, 0, 1, 2);
+ return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
}
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+ const char *dir,
int fhin, int fhout, int fherr)
{
pid_t pid;
@@ -756,14 +774,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
pid = -1;
}
else {
- pid = mingw_spawnve_fd(iprog, argv, env, 1,
+ pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
fhin, fhout, fherr);
free(iprog);
}
argv[0] = argv0;
}
else
- pid = mingw_spawnve_fd(prog, argv, env, 0,
+ pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
fhin, fhout, fherr);
free(prog);
}
diff --git a/compat/mingw.h b/compat/mingw.h
index e81e752ed2..7c2ab64cb4 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -229,6 +229,7 @@ int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+ const char *dir,
int fhin, int fhout, int fherr);
void mingw_execvp(const char *cmd, char *const *argv);
#define execvp mingw_execvp
diff --git a/compat/vcbuild/include/termios.h b/compat/vcbuild/include/termios.h
new file mode 100644
index 0000000000..0d8552a2c6
--- /dev/null
+++ b/compat/vcbuild/include/termios.h
@@ -0,0 +1 @@
+/* Intentionally empty file to support building git with MSVC */
diff --git a/configure.ac b/configure.ac
index 914ae5759f..f4d7372ef8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -179,6 +179,26 @@ fi],
AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads.])
])
+# Define option to enable JavaScript minification
+AC_ARG_ENABLE([jsmin],
+[AS_HELP_STRING([--enable-jsmin=PATH],
+ [PATH is the name of a JavaScript minifier or the absolute path to one.])],
+[
+ JSMIN=$enableval;
+ AC_MSG_NOTICE([Setting JSMIN to '$JSMIN' to enable JavaScript minifying])
+ GIT_CONF_APPEND_LINE(JSMIN=$enableval);
+])
+
+# Define option to enable CSS minification
+AC_ARG_ENABLE([cssmin],
+[AS_HELP_STRING([--enable-cssmin=PATH],
+ [PATH is the name of a CSS minifier or the absolute path to one.])],
+[
+ CSSMIN=$enableval;
+ AC_MSG_NOTICE([Setting CSSMIN to '$CSSMIN' to enable CSS minifying])
+ GIT_CONF_APPEND_LINE(CSSMIN=$enableval);
+])
+
## Site configuration (override autodetection)
## --with-PACKAGE[=ARG] and --without-PACKAGE
AC_MSG_NOTICE([CHECKS for site configuration])
diff --git a/contrib/ciabot/README b/contrib/ciabot/README
new file mode 100644
index 0000000000..3b916acece
--- /dev/null
+++ b/contrib/ciabot/README
@@ -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
index 0000000000..d0627e0852
--- /dev/null
+++ b/contrib/ciabot/ciabot.py
@@ -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
index 0000000000..eb87bba38e
--- /dev/null
+++ b/contrib/ciabot/ciabot.sh
@@ -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 :
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 733ac39a32..545bd4b383 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -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 ()
diff --git a/contrib/fast-import/import-zips.py b/contrib/fast-import/import-zips.py
index 7051a83a59..82f5ed3ddc 100755
--- a/contrib/fast-import/import-zips.py
+++ b/contrib/fast-import/import-zips.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
## zip archive frontend for git-fast-import
##
diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py
index 854cd94ba5..046cb2b268 100755
--- a/contrib/hg-to-git/hg-to-git.py
+++ b/contrib/hg-to-git/hg-to-git.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#!/usr/bin/env python
""" hg-to-git.py - A Mercurial to GIT converter
diff --git a/contrib/p4import/git-p4import.py b/contrib/p4import/git-p4import.py
index 0f3d97b67e..b6e534b65b 100644
--- a/contrib/p4import/git-p4import.py
+++ b/contrib/p4import/git-p4import.py
@@ -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.
diff --git a/daemon.c b/daemon.c
index 7d9e1c03e8..a90ab10505 100644
--- 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 f5d93e9694..e40c1271da 100644
--- a/diff.c
+++ b/diff.c
@@ -14,6 +14,7 @@
#include "userdiff.h"
#include "sigchain.h"
#include "submodule.h"
+#include "ll-merge.h"
#ifdef NO_FAST_WORKING_DIRECTORY
#define FAST_WORKING_DIRECTORY 0
@@ -550,6 +551,10 @@ static void emit_rewrite_diff(const char *name_a,
emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
if (lc_b)
emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
+ if (textconv_one)
+ free((char *)data_one);
+ if (textconv_two)
+ free((char *)data_two);
}
struct diff_words_buffer {
@@ -695,7 +700,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
{
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
mmfile_t minus, plus;
/* special case: only removal */
@@ -717,7 +721,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
/* as only the hunk header will be parsed, we need a 0-context */
xecfg.ctxlen = 0;
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
free(minus.ptr);
free(plus.ptr);
if (diff_words->current_plus != diff_words->plus.text.ptr +
@@ -948,7 +952,7 @@ struct diffstat_t {
unsigned is_unmerged:1;
unsigned is_binary:1;
unsigned is_renamed:1;
- unsigned int added, deleted;
+ uintmax_t added, deleted;
} **files;
};
@@ -1040,7 +1044,7 @@ static void fill_print_name(struct diffstat_file *file)
static void show_stats(struct diffstat_t *data, struct diff_options *options)
{
int i, len, add, del, adds = 0, dels = 0;
- int max_change = 0, max_len = 0;
+ uintmax_t max_change = 0, max_len = 0;
int total_files = data->nr;
int width, name_width;
const char *reset, *set, *add_c, *del_c;
@@ -1069,7 +1073,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
for (i = 0; i < data->nr; i++) {
struct diffstat_file *file = data->files[i];
- int change = file->added + file->deleted;
+ uintmax_t change = file->added + file->deleted;
fill_print_name(file);
len = strlen(file->print_name);
if (max_len < len)
@@ -1097,8 +1101,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
for (i = 0; i < data->nr; i++) {
const char *prefix = "";
char *name = data->files[i]->print_name;
- int added = data->files[i]->added;
- int deleted = data->files[i]->deleted;
+ uintmax_t added = data->files[i]->added;
+ uintmax_t deleted = data->files[i]->deleted;
int name_len;
/*
@@ -1119,9 +1123,11 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
if (data->files[i]->is_binary) {
show_name(options->file, prefix, name, len);
fprintf(options->file, " Bin ");
- fprintf(options->file, "%s%d%s", del_c, deleted, reset);
+ fprintf(options->file, "%s%"PRIuMAX"%s",
+ del_c, deleted, reset);
fprintf(options->file, " -> ");
- fprintf(options->file, "%s%d%s", add_c, added, reset);
+ fprintf(options->file, "%s%"PRIuMAX"%s",
+ add_c, added, reset);
fprintf(options->file, " bytes");
fprintf(options->file, "\n");
continue;
@@ -1150,7 +1156,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
del = scale_linear(del, width, max_change);
}
show_name(options->file, prefix, name, len);
- fprintf(options->file, "%5d%s", added + deleted,
+ fprintf(options->file, "%5"PRIuMAX"%s", added + deleted,
added + deleted ? " " : "");
show_graph(options->file, '+', add, add_c, reset);
show_graph(options->file, '-', del, del_c, reset);
@@ -1200,7 +1206,8 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options)
fprintf(options->file, "-\t-\t");
else
fprintf(options->file,
- "%d\t%d\t", file->added, file->deleted);
+ "%"PRIuMAX"\t%"PRIuMAX"\t",
+ file->added, file->deleted);
if (options->line_termination) {
fill_print_name(file);
if (!file->is_renamed)
@@ -1370,37 +1377,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 +1410,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 +1419,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",
@@ -1704,7 +1707,6 @@ static void builtin_diff(const char *name_a,
const char *diffopts = getenv("GIT_DIFF_OPTS");
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
struct emit_callback ecbdata;
const struct userdiff_funcname *pe;
@@ -1776,7 +1778,7 @@ static void builtin_diff(const char *name_a,
}
}
xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
free_diff_words_data(&ecbdata);
if (textconv_one)
@@ -1829,13 +1831,12 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
/* Crazy xdl interfaces.. */
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
}
free_and_return:
@@ -1860,6 +1861,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
data.lineno = 0;
data.o = o;
data.ws_rule = whitespace_rule(attr_path);
+ data.conflict_marker_size = ll_merge_marker_size(attr_path);
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
die("unable to read files to diff");
@@ -1876,14 +1878,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
/* Crazy xdl interfaces.. */
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 1; /* at least one context line */
xpp.flags = XDF_NEED_MINIMAL;
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
if (data.ws_rule & WS_BLANK_AT_EOF) {
struct emit_callback ecbdata;
@@ -3378,7 +3379,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
for (i = 0; i < q->nr; i++) {
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
mmfile_t mf1, mf2;
struct diff_filepair *p = q->queue[i];
int len1, len2;
@@ -3440,7 +3440,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
xecfg.ctxlen = 3;
xecfg.flags = XDL_EMIT_FUNCNAMES;
xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
}
git_SHA1_Final(sha1, &ctx);
@@ -3883,6 +3883,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 +3894,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);
diff --git a/git-compat-util.h b/git-compat-util.h
index 3ebf96690a..6e25977289 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -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);
diff --git a/git-difftool.perl b/git-difftool.perl
index d975d072db..adc42de875 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -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') {
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 6a65f255cc..f6080149c2 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -212,7 +212,7 @@ server.errorlog = "$fqgitdir/gitweb/error.log"
# variable above and uncomment this
#accesslog.filename = "$fqgitdir/gitweb/access.log"
-setenv.add-environment = ( "PATH" => "/usr/local/bin:/usr/bin:/bin" )
+setenv.add-environment = ( "PATH" => env.PATH )
cgi.assign = ( ".cgi" => "" )
@@ -361,7 +361,7 @@ error_log $fqgitdir/gitweb/error.log
access_log $fqgitdir/gitweb/access.log
#cgi setup
-cgi_env PATH=/usr/local/bin:/usr/bin:/bin,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH
+cgi_env PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH
cgi_interp $PERL
cgi_ext cgi,pl
@@ -391,18 +391,20 @@ EOFGITWEB
gitweb_css () {
cat > "$1" <<\EOFGITWEB
@@GITWEB_CSS@@
+
EOFGITWEB
}
gitweb_js () {
cat > "$1" <<\EOFGITWEB
@@GITWEB_JS@@
+
EOFGITWEB
}
gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi"
-gitweb_css "$GIT_DIR/gitweb/gitweb.css"
-gitweb_js "$GIT_DIR/gitweb/gitweb.js"
+gitweb_css "$GIT_DIR/@@GITWEB_CSS_NAME@@"
+gitweb_js "$GIT_DIR/@@GITWEB_JS_NAME@@"
case "$httpd" in
*lighttpd*)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 415ae72dbc..436b7f5977 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -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"
@@ -571,6 +565,7 @@ do_next () {
git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
} &&
{
+ test -s "$REWRITTEN_LIST" &&
git notes copy --for-rewrite=rebase < "$REWRITTEN_LIST" ||
true # we don't care if this copying failed
} &&
@@ -732,9 +727,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 +786,9 @@ first and then run 'git rebase --continue' again."
-i)
# yeah, we know
;;
+ --no-ff)
+ NEVER_FF=t
+ ;;
--root)
REBASE_ROOT=t
;;
@@ -831,8 +830,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 +972,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
diff --git a/git-rebase.sh b/git-rebase.sh
index e0eb9568f3..44f5c65fdb 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -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)
diff --git a/git-send-email.perl b/git-send-email.perl
index d612ae8729..ce569a9c8f 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -64,6 +64,8 @@ git send-email [options] <file | directory | rev-list options >
--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 @@ my $have_email_valid = eval { require Email::Valid; 1 };
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 @@ my $compose_filename;
# 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 @@ my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
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 @@ my $rc = GetOptions("sender|from=s" => \$sender,
"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 @@ X-Mailer: git-send-email $gitversion
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 @@ X-Mailer: git-send-email $gitversion
}
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) {
diff --git a/git-stash.sh b/git-stash.sh
index aa47e541ee..59db3dc38e 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -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
}
diff --git a/git-submodule.sh b/git-submodule.sh
index 2dd372a21d..3319b836b2 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -21,6 +21,8 @@ command=
branch=
reference=
cached=
+recursive=
+init=
files=
nofetch=
update=
diff --git a/git.spec.in b/git.spec.in
index ee74a5eed7..9533147ff2 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -127,6 +127,9 @@ find $RPM_BUILD_ROOT -type f -name perllocal.pod -exec rm -f {} ';'
rm -rf $RPM_BUILD_ROOT%{_mandir}
%endif
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
+install -m 644 -T contrib/completion/git-completion.bash $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/git
+
%clean
rm -rf $RPM_BUILD_ROOT
@@ -136,6 +139,7 @@ rm -rf $RPM_BUILD_ROOT
%doc README COPYING Documentation/*.txt
%{!?_without_docs: %doc Documentation/*.html Documentation/howto}
%{!?_without_docs: %doc Documentation/technical}
+%{_sysconfdir}/bash_completion.d
%files svn
%defattr(-,root,root)
@@ -192,6 +196,9 @@ rm -rf $RPM_BUILD_ROOT
# No files for you!
%changelog
+* Fri Mar 26 2010 Ian Ward Comfort <icomfort@stanford.edu>
+- Ship bash completion support from contrib/ in the core package.
+
* Sun Jan 31 2010 Junio C Hamano <gitster@pobox.com>
- Do not use %define inside %{!?...} construct.
diff --git a/git_remote_helpers/Makefile b/git_remote_helpers/Makefile
index c62dfd0f4d..74b05dc91e 100644
--- a/git_remote_helpers/Makefile
+++ b/git_remote_helpers/Makefile
@@ -7,7 +7,11 @@ pysetupfile:=setup.py
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
ifndef PYTHON_PATH
- PYTHON_PATH = /usr/bin/python
+ ifeq ($(uname_S),FreeBSD)
+ PYTHON_PATH = /usr/local/bin/python
+ else
+ PYTHON_PATH = /usr/bin/python
+ endif
endif
ifndef prefix
prefix = $(HOME)
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 1f36a3e815..1b0e09a561 100644
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -1877,8 +1877,11 @@ proc setoptions {} {
option add *Menubutton.font uifont startupFile
option add *Label.font uifont startupFile
option add *Message.font uifont startupFile
- option add *Entry.font uifont startupFile
+ option add *Entry.font textfont startupFile
+ option add *Text.font textfont startupFile
option add *Labelframe.font uifont startupFile
+ option add *Spinbox.font textfont startupFile
+ option add *Listbox.font mainfont startupFile
}
# Make a menu and submenus.
@@ -2174,7 +2177,7 @@ proc makewindow {} {
set findstring {}
set fstring .tf.lbar.findstring
lappend entries $fstring
- ${NS}::entry $fstring -width 30 -font textfont -textvariable findstring
+ ${NS}::entry $fstring -width 30 -textvariable findstring
trace add variable findstring write find_change
set findtype [mc "Exact"]
set findtypemenu [makedroplist .tf.lbar.findtype \
@@ -2217,7 +2220,7 @@ proc makewindow {} {
pack .bleft.top.search -side left -padx 5
set sstring .bleft.top.sstring
set searchstring ""
- ${NS}::entry $sstring -width 20 -font textfont -textvariable searchstring
+ ${NS}::entry $sstring -width 20 -textvariable searchstring
lappend entries $sstring
trace add variable searchstring write incrsearch
pack $sstring -side left -expand 1 -fill x
@@ -2229,7 +2232,7 @@ proc makewindow {} {
-command changediffdisp -variable diffelide -value {1 0}
${NS}::label .bleft.mid.labeldiffcontext -text " [mc "Lines of context"]: "
pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
- spinbox .bleft.mid.diffcontext -width 5 -font textfont \
+ spinbox .bleft.mid.diffcontext -width 5 \
-from 0 -increment 1 -to 10000000 \
-validate all -validatecommand "diffcontextvalidate %P" \
-textvariable diffcontextstring
@@ -2383,6 +2386,8 @@ proc makewindow {} {
}
bindall <$::BM> "canvscan mark %W %x %y"
bindall <B$::BM-Motion> "canvscan dragto %W %x %y"
+ bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
+ bind . <$M1B-Key-w> doquit
bindkey <Home> selfirstline
bindkey <End> sellastline
bind . <Key-Up> "selnextline -1"
@@ -2782,7 +2787,7 @@ proc about {} {
message $w.m -text [mc "
Gitk - a commit viewer for git
-Copyright © 2005-2009 Paul Mackerras
+Copyright \u00a9 2005-2010 Paul Mackerras
Use and redistribute under the terms of the GNU General Public License"] \
-justify center -aspect 400 -border 2 -bg white -relief groove
@@ -2814,6 +2819,7 @@ proc keys {} {
[mc "Gitk key bindings:"]
[mc "<%s-Q> Quit" $M1T]
+[mc "<%s-W> Close window" $M1T]
[mc "<Home> Move to first commit"]
[mc "<End> Move to last commit"]
[mc "<Up>, p, i Move up one commit"]
@@ -3805,10 +3811,10 @@ proc newview {ishighlight} {
raise $top
return
}
+ decode_view_opts $nextviewnum $revtreeargs
set newviewname($nextviewnum) "[mc "View"] $nextviewnum"
set newviewopts($nextviewnum,perm) 0
set newviewopts($nextviewnum,cmd) $viewargscmd($curview)
- decode_view_opts $nextviewnum $revtreeargs
vieweditor $top $nextviewnum [mc "Gitk view definition"]
}
@@ -3845,6 +3851,7 @@ set known_view_options {
{cmd t50= + {} {mc "Command to generate more commits to include:"}}
}
+# Convert $newviewopts($n, ...) into args for git log.
proc encode_view_opts {n} {
global known_view_options newviewopts
@@ -3878,6 +3885,7 @@ proc encode_view_opts {n} {
return [concat $rargs [shellsplit $newviewopts($n,args)]]
}
+# Fill $newviewopts($n, ...) based on args for git log.
proc decode_view_opts {n view_args} {
global known_view_options newviewopts
@@ -3960,10 +3968,10 @@ proc editview {} {
raise $top
return
}
+ decode_view_opts $curview $viewargs($curview)
set newviewname($curview) $viewname($curview)
set newviewopts($curview,perm) $viewperm($curview)
set newviewopts($curview,cmd) $viewargscmd($curview)
- decode_view_opts $curview $viewargs($curview)
vieweditor $top $curview "[mc "Gitk: edit view"] $viewname($curview)"
}
@@ -4037,7 +4045,7 @@ proc vieweditor {top n title} {
} elseif {$type eq "path"} {
${NS}::label $top.l -text $title
pack $top.l -in $top -side top -pady [list 3 0] -anchor w -padx 3
- text $top.t -width 40 -height 5 -background $bgcolor -font uifont
+ text $top.t -width 40 -height 5 -background $bgcolor
if {[info exists viewfiles($n)]} {
foreach f $viewfiles($n) {
$top.t insert end $f
@@ -7501,7 +7509,7 @@ proc getblobdiffs {ids} {
global ignorespace
global limitdiffs vfilelimit curview
global diffencoding targetline diffnparents
- global git_version
+ global git_version currdiffsubmod
set textconv {}
if {[package vcompare $git_version "1.6.1"] >= 0} {
@@ -7528,6 +7536,7 @@ proc getblobdiffs {ids} {
set diffencoding [get_path_encoding {}]
fconfigure $bdf -blocking 0 -encoding binary -eofchar {}
set blobdifffd($ids) $bdf
+ set currdiffsubmod ""
filerun $bdf [list getblobdiffline $bdf $diffids]
}
@@ -7598,7 +7607,7 @@ proc getblobdiffline {bdf ids} {
global diffnexthead diffnextnote difffilestart
global ctext_file_names ctext_file_lines
global diffinhdr treediffs mergemax diffnparents
- global diffencoding jump_to_here targetline diffline
+ global diffencoding jump_to_here targetline diffline currdiffsubmod
set nr 0
$ctext conf -state normal
@@ -7679,19 +7688,30 @@ proc getblobdiffline {bdf ids} {
} elseif {![string compare -length 10 "Submodule " $line]} {
# start of a new submodule
- if {[string compare [$ctext get "end - 4c" end] "\n \n\n"]} {
+ if {[regexp -indices "\[0-9a-f\]+\\.\\." $line nameend]} {
+ set fname [string range $line 10 [expr [lindex $nameend 0] - 2]]
+ } else {
+ set fname [string range $line 10 [expr [string first "contains " $line] - 2]]
+ }
+ if {$currdiffsubmod != $fname} {
$ctext insert end "\n"; # Add newline after commit message
}
set curdiffstart [$ctext index "end - 1c"]
lappend ctext_file_names ""
- set fname [string range $line 10 [expr [string last " " $line] - 1]]
- lappend ctext_file_lines $fname
- makediffhdr $fname $ids
- $ctext insert end "\n$line\n" filesep
+ if {$currdiffsubmod != $fname} {
+ lappend ctext_file_lines $fname
+ makediffhdr $fname $ids
+ set currdiffsubmod $fname
+ $ctext insert end "\n$line\n" filesep
+ } else {
+ $ctext insert end "$line\n" filesep
+ }
} elseif {![string compare -length 3 " >" $line]} {
+ set $currdiffsubmod ""
set line [encoding convertfrom $diffencoding $line]
$ctext insert end "$line\n" dresult
} elseif {![string compare -length 3 " <" $line]} {
+ set $currdiffsubmod ""
set line [encoding convertfrom $diffencoding $line]
$ctext insert end "$line\n" d0
} elseif {$diffinhdr} {
@@ -8527,7 +8547,7 @@ proc do_cmp_commits {a b} {
}
proc diffcommits {a b} {
- global diffcontext diffids blobdifffd diffinhdr
+ global diffcontext diffids blobdifffd diffinhdr currdiffsubmod
set tmpdir [gitknewtmpdir]
set fna [file join $tmpdir "commit-[string range $a 0 7]"]
@@ -8548,6 +8568,7 @@ proc diffcommits {a b} {
set diffids [list commits $a $b]
set blobdifffd($diffids) $fd
set diffinhdr 0
+ set currdiffsubmod ""
filerun $fd [list getblobdiffline $fd $diffids]
}
@@ -10528,7 +10549,6 @@ proc mkfontdisp {font top which} {
set fontpref($font) [set $font]
${NS}::button $top.${font}but -text $which \
-command [list choosefont $font $which]
- if {!$use_ttk} {$top.${font}but configure -font optionfont}
${NS}::label $top.$font -relief flat -font $font \
-text $fontattr($font,family) -justify left
grid x $top.${font}but $top.$font -sticky w
@@ -10791,15 +10811,6 @@ proc doprefs {} {
mkfontdisp textfont $top [mc "Diff display font"]
mkfontdisp uifont $top [mc "User interface font"]
- if {!$use_ttk} {
- foreach w {maxpctl maxwidthl showlocal autoselect tabstopl ntag
- ldiff lattr extdifff.l extdifff.b bgbut fgbut
- diffoldbut diffnewbut hunksepbut markbgbut selbgbut
- want_ttk ttk_note} {
- $top.$w configure -font optionfont
- }
- }
-
${NS}::frame $top.buts
${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
${NS}::button $top.buts.can -text [mc "Cancel"] -command prefscan -default normal
@@ -10849,6 +10860,7 @@ proc setselbg {c} {
# radiobuttons look bad. This chooses white for selectColor if the
# background color is light, or black if it is dark.
proc setui {c} {
+ if {[tk windowingsystem] eq "win32"} { return }
set bg [winfo rgb . $c]
set selc black
if {[lindex $bg 0] + 1.5 * [lindex $bg 1] + 0.5 * [lindex $bg 2] > 100000} {
@@ -11411,8 +11423,6 @@ namespace import ::msgcat::mc
catch {source ~/.gitk}
-font create optionfont -family sans-serif -size -12
-
parsefont mainfont $mainfont
eval font create mainfont [fontflags mainfont]
eval font create mainfontbold [fontflags mainfont 1]
@@ -11613,3 +11623,9 @@ if {[tk windowingsystem] eq "win32"} {
}
getcommits {}
+
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: t
+# tab-width: 8
+# End:
diff --git a/gitk-git/po/de.po b/gitk-git/po/de.po
index c79aa9cbc8..bd194a3dff 100644
--- a/gitk-git/po/de.po
+++ b/gitk-git/po/de.po
@@ -334,14 +334,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright ©9 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - eine Visualisierung der Git-Historie\n"
"\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Benutzung und Weiterverbreitung gemäß den Bedingungen der GNU General Public License"
diff --git a/gitk-git/po/es.po b/gitk-git/po/es.po
index 0e19b5eae2..0471dd0672 100644
--- a/gitk-git/po/es.po
+++ b/gitk-git/po/es.po
@@ -281,14 +281,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - un visualizador de revisiones para git\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Uso y redistribución permitidos según los términos de la Licencia Pública "
"General de GNU (GNU GPL)"
diff --git a/gitk-git/po/fr.po b/gitk-git/po/fr.po
index cb0e1edc63..5370ddc393 100644
--- a/gitk-git/po/fr.po
+++ b/gitk-git/po/fr.po
@@ -334,14 +334,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - visualisateur de commit pour git\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Utilisation et redistribution soumises aux termes de la GNU General Public "
"License"
diff --git a/gitk-git/po/hu.po b/gitk-git/po/hu.po
index 1df212e881..7262b610dc 100644
--- a/gitk-git/po/hu.po
+++ b/gitk-git/po/hu.po
@@ -333,14 +333,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright ©9 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - commit nézegető a githez\n"
"\n"
-"Szerzői jog ©9 2005-2009 Paul Mackerras\n"
+"Szerzői jog \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Használd és terjeszd a GNU General Public License feltételei mellett"
diff --git a/gitk-git/po/it.po b/gitk-git/po/it.po
index 4818652309..a730d63a42 100644
--- a/gitk-git/po/it.po
+++ b/gitk-git/po/it.po
@@ -334,14 +334,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - un visualizzatore di revisioni per git\n"
"\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Utilizzo e redistribuzione permessi sotto i termini della GNU General Public "
"License"
diff --git a/gitk-git/po/ja.po b/gitk-git/po/ja.po
index c0c92addb4..4f4705164c 100644
--- a/gitk-git/po/ja.po
+++ b/gitk-git/po/ja.po
@@ -335,14 +335,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - gitコミットビューア\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"使用および再配布は GNU General Public License に従ってください"
diff --git a/gitk-git/po/ru.po b/gitk-git/po/ru.po
index 704eba8f9d..c3d0285b24 100644
--- a/gitk-git/po/ru.po
+++ b/gitk-git/po/ru.po
@@ -313,14 +313,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - программа просмотра истории репозиториев Git\n"
"\n"
-"Copyright (c) 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Использование и распространение согласно условиям GNU General Public License"
diff --git a/gitk-git/po/sv.po b/gitk-git/po/sv.po
index 0f5e2fd8d7..386763ade7 100644
--- a/gitk-git/po/sv.po
+++ b/gitk-git/po/sv.po
@@ -334,14 +334,14 @@ msgid ""
"\n"
"Gitk - a commit viewer for git\n"
"\n"
-"Copyright ©9 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Use and redistribute under the terms of the GNU General Public License"
msgstr ""
"\n"
"Gitk - en incheckningsvisare för git\n"
"\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
"\n"
"Använd och vidareförmedla enligt villkoren i GNU General Public License"
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index b76a0cffff..cbdc136470 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -2,11 +2,11 @@ GIT web Interface (gitweb) Installation
=======================================
First you have to generate gitweb.cgi from gitweb.perl using
-"make gitweb/gitweb.cgi", then copy appropriate files (gitweb.cgi,
+"make gitweb", then copy appropriate files (gitweb.cgi, gitweb.js,
gitweb.css, git-logo.png and git-favicon.png) to their destination.
For example if git was (or is) installed with /usr prefix, you can do
- $ make prefix=/usr gitweb/gitweb.cgi ;# as yourself
+ $ make prefix=/usr gitweb ;# as yourself
# cp gitweb/git* /var/www/cgi-bin/ ;# as root
Alternatively you can use autoconf generated ./configure script to
@@ -15,7 +15,7 @@ instead
$ make configure ;# as yourself
$ ./configure --prefix=/usr ;# as yourself
- $ make gitweb/gitweb.cgi ;# as yourself
+ $ make gitweb ;# as yourself
# cp gitweb/git* /var/www/cgi-bin/ ;# as root
The above example assumes that your web server is configured to run
@@ -31,8 +31,7 @@ file for gitweb (in gitweb/README).
- There are many configuration variables which affect building of
gitweb.cgi; see "default configuration for gitweb" section in main
- (top dir) Makefile, and instructions for building gitweb/gitweb.cgi
- target.
+ (top dir) Makefile, and instructions for building gitweb target.
One of the most important is where to find the git wrapper binary. Gitweb
tries to find the git wrapper at $(bindir)/git, so you have to set $bindir
@@ -62,9 +61,15 @@ file for gitweb (in gitweb/README).
a suggestion).
- You can control where gitweb tries to find its main CSS style file,
- its favicon and logo with the GITWEB_CSS, GITWEB_FAVICON and GITWEB_LOGO
- build configuration variables. By default gitweb tries to find them
- in the same directory as gitweb.cgi script.
+ its JavaScript file, its favicon and logo with the GITWEB_CSS, GITWEB_JS
+ GITWEB_FAVICON and GITWEB_LOGO build configuration variables. By default
+ gitweb tries to find them in the same directory as gitweb.cgi script.
+
+- You can optionally generate minified versions of gitweb.js and gitweb.css
+ by defining the JSMIN and CSSMIN build configuration variables. By default
+ the non-minified versions will be used. NOTE: if you enable this option,
+ substitute gitweb.min.js and gitweb.min.css for all uses of gitweb.js and
+ gitweb.css in the help files.
Build example
~~~~~~~~~~~~~
@@ -74,13 +79,14 @@ Build example
we want to display are under /home/local/scm, you can do
make GITWEB_PROJECTROOT="/home/local/scm" \
+ GITWEB_JS="/gitweb/gitweb.js" \
GITWEB_CSS="/gitweb/gitweb.css" \
GITWEB_LOGO="/gitweb/git-logo.png" \
GITWEB_FAVICON="/gitweb/git-favicon.png" \
bindir=/usr/local/bin \
- gitweb/gitweb.cgi
+ gitweb
- cp -fv ~/git/gitweb/gitweb.{cgi,css} \
+ cp -fv ~/git/gitweb/gitweb.{cgi,js,css} \
~/git/gitweb/git-{favicon,logo}.png \
/var/www/cgi-bin/gitweb/
diff --git a/gitweb/Makefile b/gitweb/Makefile
index c9eb1ee667..f2e1d92fbb 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -6,14 +6,14 @@ all::
# Define JSMIN to point to JavaScript minifier that functions as
# a filter to have gitweb.js minified.
#
+# Define CSSMIN to point to a CSS minifier in order to generate a minified
+# version of gitweb.css
+#
prefix ?= $(HOME)
bindir ?= $(prefix)/bin
RM ?= rm -f
-# JavaScript minifier invocation that can function as filter
-JSMIN ?=
-
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
@@ -29,11 +29,7 @@ GITWEB_HOMETEXT = indextext.html
GITWEB_CSS = gitweb.css
GITWEB_LOGO = git-logo.png
GITWEB_FAVICON = git-favicon.png
-ifdef JSMIN
-GITWEB_JS = gitweb.min.js
-else
GITWEB_JS = gitweb.js
-endif
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =
@@ -85,45 +81,54 @@ endif
all:: gitweb.cgi
ifdef JSMIN
-FILES=gitweb.cgi gitweb.min.js
-gitweb.cgi: gitweb.perl gitweb.min.js
-else # !JSMIN
-FILES=gitweb.cgi
-gitweb.cgi: gitweb.perl
-endif # JSMIN
-
-gitweb.cgi:
+GITWEB_JS = gitweb.min.js
+all:: gitweb.min.js
+gitweb.min.js: gitweb.js GITWEB-BUILD-OPTIONS
+ $(QUIET_GEN)$(JSMIN) <$< >$@
+endif
+
+ifdef CSSMIN
+GITWEB_CSS = gitweb.min.css
+all:: gitweb.min.css
+gitweb.min.css: gitweb.css GITWEB-BUILD-OPTIONS
+ $(QUIET_GEN)$(CSSMIN) <$ >$@
+endif
+
+GITWEB_REPLACE = \
+ -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
+ -e 's|++GIT_BINDIR++|$(bindir)|g' \
+ -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+ -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
+ -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
+ -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
+ -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
+ -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
+ -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
+ -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
+ -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
+ -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
+ -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
+ -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
+ -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
+ -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
+ -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
+ -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
+ -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g'
+
+GITWEB-BUILD-OPTIONS: FORCE
+ @rm -f $@+
+ @echo "x" '$(PERL_PATH_SQ)' $(GITWEB_REPLACE) "$(JSMIN)|$(CSSMIN)" >$@+
+ @cmp -s $@+ $@ && rm -f $@+ || mv -f $@+ $@
+
+gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
- -e 's|++GIT_BINDIR++|$(bindir)|g' \
- -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
- -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
- -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
- -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
- -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
- -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
- -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
- -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
- -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
- -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
- -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
- -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
- -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
- -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
- -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
- -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
- -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
- $< >$@+ && \
+ $(GITWEB_REPLACE) $< >$@+ && \
chmod +x $@+ && \
mv $@+ $@
-ifdef JSMIN
-gitweb.min.js: gitweb.js
- $(QUIET_GEN)$(JSMIN) <$< >$@
-endif # JSMIN
-
clean:
- $(RM) $(FILES)
+ $(RM) gitweb.cgi gitweb.min.js gitweb.min.css GITWEB-BUILD-OPTIONS
+
+.PHONY: all clean .FORCE-GIT-VERSION-FILE FORCE
-.PHONY: all clean .FORCE-GIT-VERSION-FILE
diff --git a/gitweb/README b/gitweb/README
index ad6a04c464..71742b335d 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -80,7 +80,8 @@ You can specify the following configuration variables when building GIT:
Points to the location where you put gitweb.css on your web server
(or to be more generic, the URI of gitweb stylesheet). Relative to the
base URI of gitweb. Note that you can setup multiple stylesheets from
- the gitweb config file. [Default: gitweb.css]
+ the gitweb config file. [Default: gitweb.css (or gitweb.min.css if the
+ CSSMIN variable is defined / CSS minifier is used)]
* GITWEB_LOGO
Points to the location where you put git-logo.png on your web server
(or to be more generic URI of logo, 72x27 size, displayed in top right
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a2d2283ec9..c356e95f18 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -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 fdc4206268..543b1d5378 100644
--- 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:
diff --git a/http-backend.c b/http-backend.c
index 345c12b790..d1e83d0906 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -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)
diff --git a/imap-send.c b/imap-send.c
index aeb2985b83..9d0097ca02 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -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)
diff --git a/ll-merge.c b/ll-merge.c
index 82c7742e41..f9b3d854a9 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -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);
}
diff --git a/ll-merge.h b/ll-merge.h
index 57889227b1..57754cc8ca 100644
--- a/ll-merge.h
+++ b/ll-merge.h
@@ -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);
diff --git a/merge-file.c b/merge-file.c
index fd34d76e15..c336c93c01 100644
--- a/merge-file.c
+++ b/merge-file.c
@@ -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;
diff --git a/merge-recursive.c b/merge-recursive.c
index 87232b899d..206c103635 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -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);
diff --git a/merge-recursive.h b/merge-recursive.h
index be8410ad18..d1192f56d7 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -4,6 +4,7 @@
#include "string-list.h"
struct merge_options {
+ const char *ancestor;
const char *branch1;
const char *branch2;
enum {
diff --git a/notes.h b/notes.h
index ee65bd1a24..9f59277c51 100644
--- a/notes.h
+++ b/notes.h
@@ -212,7 +212,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,
struct string_list;
struct display_notes_opt {
- int suppress_default_notes:1;
+ unsigned int suppress_default_notes:1;
struct string_list *extra_notes_refs;
};
diff --git a/parse-options.c b/parse-options.c
index c83035d013..8546d8526f 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -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;
+}
diff --git a/parse-options.h b/parse-options.h
index 9429f7e361..7581e931da 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -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);
diff --git a/pretty.c b/pretty.c
index 6ba3da89b7..7cb3a2af50 100644
--- a/pretty.c
+++ b/pretty.c
@@ -775,10 +775,13 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
}
return 0; /* unknown %g placeholder */
case 'N':
- format_display_notes(commit->object.sha1, sb,
- git_log_output_encoding ? git_log_output_encoding
- : git_commit_encoding, 0);
- return 1;
+ if (c->pretty_ctx->show_notes) {
+ format_display_notes(commit->object.sha1, sb,
+ git_log_output_encoding ? git_log_output_encoding
+ : git_commit_encoding, 0);
+ return 1;
+ }
+ return 0;
}
/* For the rest we have to parse the commit header. */
@@ -855,6 +858,35 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
return consumed + 1;
}
+static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
+ void *context)
+{
+ struct userformat_want *w = context;
+
+ if (*placeholder == '+' || *placeholder == '-')
+ placeholder++;
+
+ switch (*placeholder) {
+ case 'N':
+ w->notes = 1;
+ break;
+ }
+ return 0;
+}
+
+void userformat_find_requirements(const char *fmt, struct userformat_want *w)
+{
+ struct strbuf dummy = STRBUF_INIT;
+
+ if (!fmt) {
+ if (!user_format)
+ return;
+ fmt = user_format;
+ }
+ strbuf_expand(&dummy, user_format, userformat_want_item, w);
+ strbuf_release(&dummy);
+}
+
void format_commit_message(const struct commit *commit,
const char *format, struct strbuf *sb,
const struct pretty_print_context *pretty_ctx)
diff --git a/refs.c b/refs.c
index 0f24c8d5d9..d3db15a76c 100644
--- a/refs.c
+++ b/refs.c
@@ -1276,6 +1276,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
if (log_all_ref_updates &&
(!prefixcmp(ref_name, "refs/heads/") ||
!prefixcmp(ref_name, "refs/remotes/") ||
+ !prefixcmp(ref_name, "refs/notes/") ||
!strcmp(ref_name, "HEAD"))) {
if (safe_create_leading_directories(log_file) < 0)
return error("unable to create directory for %s",
diff --git a/rerere.c b/rerere.c
index a59f74f76c..f221bed1e9 100644
--- 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)
diff --git a/run-command.c b/run-command.c
index c8d53795ec..eb5c575629 100644
--- a/run-command.c
+++ b/run-command.c
@@ -342,8 +342,6 @@ fail_pipe:
else if (cmd->out > 1)
fhout = dup(cmd->out);
- if (cmd->dir)
- die("chdir in start_command() not implemented");
if (cmd->env)
env = make_augmented_environ(cmd->env);
@@ -353,7 +351,7 @@ fail_pipe:
cmd->argv = prepare_shell_cmd(cmd->argv);
}
- cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env,
+ cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
fhin, fhout, fherr);
failed_errno = errno;
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
diff --git a/sha1_file.c b/sha1_file.c
index a08a9d0880..ff65328006 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2271,7 +2271,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
}
static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
- void *buf, unsigned long len, time_t mtime)
+ const void *buf, unsigned long len, time_t mtime)
{
int fd, ret;
unsigned char compressed[4096];
@@ -2307,7 +2307,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
git_SHA1_Update(&c, hdr, hdrlen);
/* Then the data itself.. */
- stream.next_in = buf;
+ stream.next_in = (void *)buf;
stream.avail_in = len;
do {
unsigned char *in0 = stream.next_in;
@@ -2342,7 +2342,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
return move_temp_to_file(tmpfile, filename);
}
-int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
{
unsigned char sha1[20];
char hdr[32];
diff --git a/string-list.c b/string-list.c
index 1ac536e638..c9ad7fcd49 100644
--- a/string-list.c
+++ b/string-list.c
@@ -168,12 +168,19 @@ void sort_string_list(struct string_list *list)
qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
}
-int unsorted_string_list_has_string(struct string_list *list, const char *string)
+struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
+ const char *string)
{
int i;
for (i = 0; i < list->nr; i++)
if (!strcmp(string, list->items[i].string))
- return 1;
- return 0;
+ return list->items + i;
+ return NULL;
+}
+
+int unsorted_string_list_has_string(struct string_list *list,
+ const char *string)
+{
+ return unsorted_string_list_lookup(list, string) != NULL;
}
diff --git a/string-list.h b/string-list.h
index 6569cf607b..63b69c8d75 100644
--- a/string-list.h
+++ b/string-list.h
@@ -38,5 +38,6 @@ struct string_list_item *string_list_lookup(const char *string, struct string_li
struct string_list_item *string_list_append(const char *string, struct string_list *list);
void sort_string_list(struct string_list *list);
int unsorted_string_list_has_string(struct string_list *list, const char *string);
-
+struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
+ const char *string);
#endif /* STRING_LIST_H */
diff --git a/submodule.c b/submodule.c
index b3b8bc1479..676d48fb33 100644
--- a/submodule.c
+++ b/submodule.c
@@ -12,8 +12,15 @@ static int add_submodule_odb(const char *path)
struct strbuf objects_directory = STRBUF_INIT;
struct alternate_object_database *alt_odb;
int ret = 0;
+ const char *git_dir;
- strbuf_addf(&objects_directory, "%s/.git/objects/", path);
+ strbuf_addf(&objects_directory, "%s/.git", path);
+ git_dir = read_gitfile_gently(objects_directory.buf);
+ if (git_dir) {
+ strbuf_reset(&objects_directory);
+ strbuf_addstr(&objects_directory, git_dir);
+ }
+ strbuf_addstr(&objects_directory, "/objects/");
if (!is_directory(objects_directory.buf)) {
ret = -1;
goto done;
@@ -132,7 +139,6 @@ void show_submodule_summary(FILE *f, const char *path,
unsigned is_submodule_modified(const char *path, int ignore_untracked)
{
- int i;
ssize_t len;
struct child_process cp;
const char *argv[] = {
@@ -141,16 +147,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
NULL,
NULL,
};
- const char *env[LOCAL_REPO_ENV_SIZE + 3];
struct strbuf buf = STRBUF_INIT;
unsigned dirty_submodule = 0;
const char *line, *next_line;
+ const char *git_dir;
- for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
- env[i] = local_repo_env[i];
-
- strbuf_addf(&buf, "%s/.git/", path);
- if (!is_directory(buf.buf)) {
+ strbuf_addf(&buf, "%s/.git", path);
+ git_dir = read_gitfile_gently(buf.buf);
+ if (!git_dir)
+ git_dir = buf.buf;
+ if (!is_directory(git_dir)) {
strbuf_release(&buf);
/* The submodule is not checked out, so it is not modified */
return 0;
@@ -158,21 +164,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
}
strbuf_reset(&buf);
- strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
- env[i++] = strbuf_detach(&buf, NULL);
- strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
- env[i++] = strbuf_detach(&buf, NULL);
- env[i] = NULL;
-
if (ignore_untracked)
argv[2] = "-uno";
memset(&cp, 0, sizeof(cp));
cp.argv = argv;
- cp.env = env;
+ cp.env = local_repo_env;
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
+ cp.dir = path;
if (start_command(&cp))
die("Could not run git status --porcelain");
@@ -201,8 +202,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
if (finish_command(&cp))
die("git status --porcelain failed");
- for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
- free((char *)env[i]);
strbuf_release(&buf);
return dirty_submodule;
}
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index f4ca4fc85c..3ec9cbef2c 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -73,6 +73,27 @@ then
exit 1
fi
+clean=no
+test_expect_success 'tests clean up after themselves' '
+ test_when_finished clean=yes
+'
+
+cleaner=no
+test_expect_code 1 'tests clean up even after a failure' '
+ test_when_finished cleaner=yes &&
+ (exit 1)
+'
+
+if test $clean$cleaner != yesyes
+then
+ say "bug in test framework: cleanup commands do not work reliably"
+ exit 1
+fi
+
+test_expect_code 2 'failure to clean up causes the test to fail' '
+ test_when_finished "(exit 2)"
+'
+
################################################################
# Basics of the basics
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 9956e3ad62..b946f87686 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -58,14 +58,12 @@ test_expect_success 'allow missing object with --missing' '
test_cmp tree.missing actual
'
-test_expect_failure 'mktree reads ls-tree -r output (1)' '
- git mktree <all >actual &&
- test_cmp tree actual
+test_expect_success 'mktree refuses to read ls-tree -r output (1)' '
+ test_must_fail git mktree <all >actual
'
-test_expect_failure 'mktree reads ls-tree -r output (2)' '
- git mktree <all.withsub >actual &&
- test_cmp tree.withsub actual
+test_expect_success 'mktree refuses to read ls-tree -r output (2)' '
+ test_must_fail git mktree <all.withsub >actual
'
test_done
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
index cc30be4a65..055ad00f77 100755
--- a/t/t1304-default-acl.sh
+++ b/t/t1304-default-acl.sh
@@ -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 &&
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index a4a0b1d6c5..64f32ad94d 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -55,6 +55,15 @@ test_expect_success 'handle empty notes gracefully' '
git notes show ; test 1 = $?
'
+test_expect_success 'show non-existent notes entry with %N' '
+ for l in A B
+ do
+ echo "$l"
+ done >expect &&
+ git show -s --format='A%n%NB' >output &&
+ test_cmp expect output
+'
+
test_expect_success 'create notes' '
git config core.notesRef refs/notes/commits &&
MSG=b4 git notes add &&
@@ -65,6 +74,24 @@ test_expect_success 'create notes' '
test_must_fail git notes show HEAD^
'
+test_expect_success 'show notes entry with %N' '
+ for l in A b4 B
+ do
+ echo "$l"
+ done >expect &&
+ git show -s --format='A%n%NB' >output &&
+ test_cmp expect output
+'
+
+cat >expect <<EOF
+d423f8c refs/notes/commits@{0}: notes: Notes added by 'git notes add'
+EOF
+
+test_expect_success 'create reflog entry' '
+ git reflog show refs/notes/commits >output &&
+ test_cmp expect output
+'
+
test_expect_success 'edit existing notes' '
MSG=b3 git notes edit &&
test ! -f .git/NOTES_EDITMSG &&
@@ -378,6 +405,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 &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 19668c2c92..f20ea38411 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -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 &&
@@ -50,6 +56,11 @@ test_expect_success 'setup' '
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
index 0000000000..e17ae712b1
--- /dev/null
+++ b/t/t3506-cherry-pick-ff.sh
@@ -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 100755
index 0000000000..e25cf8039a
--- /dev/null
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -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
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index c7b625642d..d21c37f3a2 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -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
diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh
index 0391a5827e..61589853df 100755
--- a/t/t4017-diff-retval.sh
+++ b/t/t4017-diff-retval.sh
@@ -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
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
index 7584efa36b..40277c77aa 100755
--- a/t/t4038-diff-combined.sh
+++ b/t/t4038-diff-combined.sh
@@ -81,4 +81,12 @@ test_expect_success 'check combined output (2)' '
verify_helper sidesansone
'
+test_expect_success 'diagnose truncated file' '
+ >file &&
+ git add file &&
+ git commit --amend -C HEAD &&
+ git show >out &&
+ grep "diff --cc file" out
+'
+
test_done
diff --git a/t/t4041-diff-submodule.sh b/t/t4041-diff-submodule.sh
index 11b19972ca..019acb926d 100755
--- a/t/t4041-diff-submodule.sh
+++ b/t/t4041-diff-submodule.sh
@@ -329,4 +329,19 @@ index 0000000..$head7
EOF
"
+test_expect_success 'setup .git file for sm2' '
+ (cd sm2 &&
+ REAL="$(pwd)/../.real" &&
+ mv .git "$REAL"
+ echo "gitdir: $REAL" >.git)
+'
+
+test_expect_success 'diff --submodule with .git file' '
+ git diff --submodule HEAD^ >actual &&
+ diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+'
+
test_done
diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh
index f0f91f149d..552da65a61 100755
--- a/t/t5407-post-rewrite-hook.sh
+++ b/t/t5407-post-rewrite-hook.sh
@@ -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
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 2692050209..230c0cd784 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -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
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 214756731b..678cee502d 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -34,7 +34,7 @@ test_expect_success 'clone with excess parameters (2)' '
test_expect_success 'output from clone' '
rm -fr dst &&
git clone -n "file://$(pwd)/src" dst >output &&
- test $(grep Initialized output | wc -l) = 1
+ test $(grep Clon output | wc -l) = 1
'
test_expect_success 'clone does not keep pack' '
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index b0047d3c6b..a49b7c5722 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -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 >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
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index 5034dd1352..d486d73994 100755
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -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;
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 42f6fff373..42f8ece097 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -7,65 +7,69 @@ test_description='fmt-merge-msg test'
. ./test-lib.sh
-datestamp=1151939923
-setdate () {
- GIT_COMMITTER_DATE="$datestamp +0200"
- GIT_AUTHOR_DATE="$datestamp +0200"
- datestamp=`expr "$datestamp" + 1`
- export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-}
-
test_expect_success setup '
echo one >one &&
git add one &&
- setdate &&
+ test_tick &&
git commit -m "Initial" &&
+ git clone . remote &&
+
echo uno >one &&
echo dos >two &&
git add two &&
- setdate &&
+ test_tick &&
git commit -a -m "Second" &&
git checkout -b left &&
- echo $datestamp >one &&
- setdate &&
+ echo "c1" >one &&
+ test_tick &&
git commit -a -m "Common #1" &&
- echo $datestamp >one &&
- setdate &&
+ echo "c2" >one &&
+ test_tick &&
git commit -a -m "Common #2" &&
git branch right &&
- echo $datestamp >two &&
- setdate &&
+ echo "l3" >two &&
+ test_tick &&
git commit -a -m "Left #3" &&
- echo $datestamp >two &&
- setdate &&
+ echo "l4" >two &&
+ test_tick &&
git commit -a -m "Left #4" &&
- echo $datestamp >two &&
- setdate &&
+ echo "l5" >two &&
+ test_tick &&
git commit -a -m "Left #5" &&
+ git tag tag-l5 &&
git checkout right &&
- echo $datestamp >three &&
+ echo "r3" >three &&
git add three &&
- setdate &&
+ test_tick &&
git commit -a -m "Right #3" &&
+ git tag tag-r3 &&
- echo $datestamp >three &&
- setdate &&
+ echo "r4" >three &&
+ test_tick &&
git commit -a -m "Right #4" &&
- echo $datestamp >three &&
- setdate &&
+ echo "r5" >three &&
+ test_tick &&
git commit -a -m "Right #5" &&
+ git checkout -b long &&
+ i=0 &&
+ while test $i -lt 30
+ do
+ test_commit $i one &&
+ i=$(($i+1))
+ done &&
+
git show-branch
'
@@ -113,7 +117,7 @@ test_expect_success 'merge-msg test #3-1' '
git config merge.log true &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -127,7 +131,7 @@ test_expect_success 'merge-msg test #3-2' '
git config merge.summary true &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -159,7 +163,7 @@ test_expect_success 'merge-msg test #4-1' '
git config merge.log true &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -173,7 +177,7 @@ test_expect_success 'merge-msg test #4-2' '
git config merge.summary true &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -187,7 +191,7 @@ test_expect_success 'merge-msg test #5-1' '
git config merge.log yes &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -201,7 +205,7 @@ test_expect_success 'merge-msg test #5-2' '
git config merge.summary yes &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -215,7 +219,7 @@ test_expect_success 'merge-msg -F' '
git config merge.summary yes &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left right &&
git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
@@ -229,7 +233,7 @@ test_expect_success 'merge-msg -F in subdirectory' '
git config merge.summary yes &&
git checkout master &&
- setdate &&
+ test_tick &&
git fetch . left right &&
mkdir sub &&
cp .git/FETCH_HEAD sub/FETCH_HEAD &&
@@ -240,4 +244,128 @@ test_expect_success 'merge-msg -F in subdirectory' '
test_cmp expected actual
'
+test_expect_success 'merge-msg with nothing to merge' '
+
+ git config --unset-all merge.log
+ git config --unset-all merge.summary
+ git config merge.summary yes &&
+
+ (
+ cd remote &&
+ git checkout -b unrelated &&
+ test_tick &&
+ git fetch origin &&
+ git fmt-merge-msg <.git/FETCH_HEAD >../actual
+ ) &&
+
+ test_cmp /dev/null actual
+'
+
+cat >expected <<\EOF
+Merge tag 'tag-r3'
+
+* tag 'tag-r3':
+ Right #3
+ Common #2
+ Common #1
+EOF
+
+test_expect_success 'merge-msg tag' '
+
+ git config --unset-all merge.log
+ git config --unset-all merge.summary
+ git config merge.summary yes &&
+
+ git checkout master &&
+ test_tick &&
+ git fetch . tag tag-r3 &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge tags 'tag-r3' and 'tag-l5'
+
+* tag 'tag-r3':
+ Right #3
+ Common #2
+ Common #1
+
+* tag 'tag-l5':
+ Left #5
+ Left #4
+ Left #3
+ Common #2
+ Common #1
+EOF
+
+test_expect_success 'merge-msg two tags' '
+
+ git config --unset-all merge.log
+ git config --unset-all merge.summary
+ git config merge.summary yes &&
+
+ git checkout master &&
+ test_tick &&
+ git fetch . tag tag-r3 tag tag-l5 &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge branch 'left', tag 'tag-r3'
+
+* tag 'tag-r3':
+ Right #3
+ Common #2
+ Common #1
+
+* left:
+ Left #5
+ Left #4
+ Left #3
+ Common #2
+ Common #1
+EOF
+
+test_expect_success 'merge-msg tag and branch' '
+
+ git config --unset-all merge.log
+ git config --unset-all merge.summary
+ git config merge.summary yes &&
+
+ git checkout master &&
+ test_tick &&
+ git fetch . tag tag-r3 left &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge branch 'long'
+
+* long: (35 commits)
+EOF
+
+test_expect_success 'merge-msg lots of commits' '
+
+ git checkout master &&
+ test_tick &&
+ git fetch . long &&
+
+ i=29 &&
+ while test $i -gt 9
+ do
+ echo " $i" &&
+ i=$(($i-1))
+ done >>expected &&
+ echo " ..." >>expected
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh
index 8d8b1c0e25..582d0b54f1 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -136,11 +136,11 @@ test_expect_success 'git-clean, dirty case' '
test_cmp expected result
'
-test_expect_failure 'git-apply adds file' false
-test_expect_failure 'git-apply updates file' false
-test_expect_failure 'git-apply removes file' false
-test_expect_failure 'git-mv to skip-worktree' false
-test_expect_failure 'git-mv from skip-worktree' false
-test_expect_failure 'git-checkout' false
+#TODO test_expect_failure 'git-apply adds file' false
+#TODO test_expect_failure 'git-apply updates file' false
+#TODO test_expect_failure 'git-apply removes file' false
+#TODO test_expect_failure 'git-mv to skip-worktree' false
+#TODO test_expect_failure 'git-mv from skip-worktree' false
+#TODO test_expect_failure 'git-checkout' false
test_done
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index d20ed61b48..1337fa5a22 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -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
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index aeec1f6142..3d4f85d74f 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -157,6 +157,22 @@ test_expect_success 'status with added and untracked file in modified submodule
EOF
'
+test_expect_success 'setup .git file for sub' '
+ (cd sub &&
+ rm -f new-file
+ REAL="$(pwd)/../.real" &&
+ mv .git "$REAL"
+ echo "gitdir: $REAL" >.git) &&
+ echo .real >>.gitignore &&
+ git commit -m "added .real to .gitignore" .gitignore
+'
+
+test_expect_success 'status with added file in modified submodule with .git file' '
+ (cd sub && git reset --hard && echo >foo && git add foo) &&
+ git status >output &&
+ grep "modified: sub (new commits, modified content)" output
+'
+
test_expect_success 'rm submodule contents' '
rm -rf sub/* sub/.git
'
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 19c72f55bf..1de83ef98f 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -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
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 356964e53a..d43f37ccaf 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -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 //"` &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index c582964b0d..7422bba47e 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -2,6 +2,18 @@
#
# Copyright (c) 2005 Junio C Hamano
#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see http://www.gnu.org/licenses/ .
# if --tee was passed, write the output not only to the terminal, but
# additionally to the file test-results/$BASENAME.out, too.
@@ -354,8 +366,10 @@ test_debug () {
}
test_run_ () {
+ test_cleanup=:
eval >&3 2>&4 "$1"
- eval_ret="$?"
+ eval_ret=$?
+ eval >&3 2>&4 "$test_cleanup"
return 0
}
@@ -533,6 +547,31 @@ test_cmp() {
$GIT_TEST_CMP "$@"
}
+# This function can be used to schedule some commands to be run
+# unconditionally at the end of the test to restore sanity:
+#
+# test_expect_success 'test core.capslock' '
+# git config core.capslock true &&
+# test_when_finished "git config --unset core.capslock" &&
+# hello world
+# '
+#
+# That would be roughly equivalent to
+#
+# test_expect_success 'test core.capslock' '
+# git config core.capslock true &&
+# hello world
+# git config --unset core.capslock
+# '
+#
+# except that the greeting and config --unset must both succeed for
+# the test to pass.
+
+test_when_finished () {
+ test_cleanup="{ $*
+ } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
+}
+
# Most tests can use the created repository, but some may need to create more.
# Usage: test_create_repo <directory>
test_create_repo () {
diff --git a/templates/Makefile b/templates/Makefile
index 408f0137a8..d22a71a399 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -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 >$@
diff --git a/templates/hooks--commit-msg.sample b/templates/hooks--commit-msg.sample
index 6ef1d29d09..b58d1184a9 100755
--- a/templates/hooks--commit-msg.sample
+++ b/templates/hooks--commit-msg.sample
@@ -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.
diff --git a/templates/hooks--post-update.sample b/templates/hooks--post-update.sample
index 5323b56b81..ec17ec1939 100755
--- a/templates/hooks--post-update.sample
+++ b/templates/hooks--post-update.sample
@@ -5,4 +5,4 @@
#
# To enable this hook, rename this file to "post-update".
-exec git-update-server-info
+exec git update-server-info
diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample
index 439eefda51..b187c4bb1f 100755
--- a/templates/hooks--pre-commit.sample
+++ b/templates/hooks--pre-commit.sample
@@ -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
diff --git a/templates/hooks--pre-rebase.sample b/templates/hooks--pre-rebase.sample
index be1b06e250..053f1111c0 100755
--- a/templates/hooks--pre-rebase.sample
+++ b/templates/hooks--pre-rebase.sample
@@ -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".
diff --git a/templates/hooks--prepare-commit-msg.sample b/templates/hooks--prepare-commit-msg.sample
index 365242499d..86b8f227ec 100755
--- a/templates/hooks--prepare-commit-msg.sample
+++ b/templates/hooks--prepare-commit-msg.sample
@@ -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,
@@ -22,10 +22,10 @@
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" ;;
diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample
index fd63b2d662..71ab04edc0 100755
--- a/templates/hooks--update.sample
+++ b/templates/hooks--update.sample
@@ -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
diff --git a/templates/info--exclude b/templates/info--exclude
index 2c87b72dff..a5196d1be8 100644
--- a/templates/info--exclude
+++ b/templates/info--exclude
@@ -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):
diff --git a/xdiff-interface.c b/xdiff-interface.c
index ca5e3fbae8..cd2285de1c 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -138,19 +138,20 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
xdiff_emit_consume_fn fn, void *consume_callback_data,
- xpparam_t const *xpp,
- xdemitconf_t const *xecfg, xdemitcb_t *xecb)
+ xpparam_t const *xpp, xdemitconf_t const *xecfg)
{
int ret;
struct xdiff_emit_state state;
+ xdemitcb_t ecb;
memset(&state, 0, sizeof(state));
state.consume = fn;
state.consume_callback_data = consume_callback_data;
- xecb->outf = xdiff_outf;
- xecb->priv = &state;
+ memset(&ecb, 0, sizeof(ecb));
+ ecb.outf = xdiff_outf;
+ ecb.priv = &state;
strbuf_init(&state.remainder, 0);
- ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb);
+ ret = xdi_diff(mf1, mf2, xpp, xecfg, &ecb);
strbuf_release(&state.remainder);
return ret;
}
diff --git a/xdiff-interface.h b/xdiff-interface.h
index abba70c16b..49d1116fc3 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -9,8 +9,7 @@ typedef void (*xdiff_emit_hunk_consume_fn)(void *, long, long, long);
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb);
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
xdiff_emit_consume_fn fn, void *consume_callback_data,
- xpparam_t const *xpp,
- xdemitconf_t const *xecfg, xdemitcb_t *xecb);
+ xpparam_t const *xpp, xdemitconf_t const *xecfg);
int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,
xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,
xpparam_t const *xpp, xdemitconf_t *xecfg);
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h
index a71763ade8..711048ea36 100644
--- a/xdiff/xdiff.h
+++ b/xdiff/xdiff.h
@@ -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
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 87cafa7021..6d6fc1bc5e 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -145,12 +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 j;
+ int marker3_size = (name3 ? strlen(name3) + 1 : 0);
if (marker_size <= 0)
marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
@@ -162,8 +163,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
if (!dest) {
size += marker_size + 1 + marker1_size;
} else {
- for (j = 0; j < marker_size; j++)
- dest[size++] = '<';
+ memset(dest + size, '<', marker_size);
+ size += marker_size;
if (marker1_size) {
dest[size] = ' ';
memcpy(dest + size + 1, name1, marker1_size - 1);
@@ -179,10 +180,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++] = '|';
+ memset(dest + size, '|', marker_size);
+ size += marker_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,
@@ -192,8 +198,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
if (!dest) {
size += marker_size + 1;
} else {
- for (j = 0; j < marker_size; j++)
- dest[size++] = '=';
+ memset(dest + size, '=', marker_size);
+ size += marker_size;
dest[size++] = '\n';
}
@@ -203,8 +209,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
if (!dest) {
size += marker_size + 1 + marker2_size;
} else {
- for (j = 0; j < marker_size; j++)
- dest[size++] = '>';
+ memset(dest + size, '>', marker_size);
+ size += marker_size;
if (marker2_size) {
dest[size] = ' ';
memcpy(dest + size + 1, name2, marker2_size - 1);
@@ -217,6 +223,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 +236,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 +406,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 +552,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 +561,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 +605,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);