--- /dev/null
+Git v1.8.5.6 Release Notes
+==========================
+
+Fixes since v1.8.5.5
+--------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
--- /dev/null
+Git v1.9.5 Release Notes
+========================
+
+Fixes since v1.9.4
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
--- /dev/null
+Git v2.0.5 Release Notes
+========================
+
+Fixes since v2.0.4
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
--- /dev/null
+Git v2.1.4 Release Notes
+========================
+
+Fixes since v2.1.3
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
--- /dev/null
+Git v2.2.1 Release Notes
+========================
+
+Fixes since v2.2
+----------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+ running on a case sensitive filesystem, but an attempt to check out
+ such a path with Git that runs on a case insensitive filesystem
+ would have clobbered ".git/config", which is definitely not what
+ the user would have expected. Git now prevents you from tracking
+ a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+ are mapped to ".git", e.g. "git~1/config" is treated as if it were
+ ".git/config". HFS+ has a similar issue, where certain unicode
+ codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+ it were ".git/config". Pathnames with these potential issues are
+ rejected on the affected systems. Git on systems that are not
+ affected by this issue (e.g. Linux) can also be configured to
+ reject them to ensure cross platform interoperability of the hosted
+ projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+ be confused with ".git", and with receive.fsckObjects configuration
+ set to true, an attempt to "git push" such a tree object will be
+ rejected. Such a path may not be a problem on a well behaving
+ filesystem but in order to protect those on HFS+ and on case
+ insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
--- /dev/null
+Git v2.3 Release Notes
+======================
+
+Updates since v2.2
+------------------
+
+Ports
+
+ *
+
+UI, Workflows & Features
+
+ * It was cumbersome to use "GIT_SSH" mechanism when the user wanted
+ to pass an extra set of arguments to the underlying ssh. A new
+ environment variable GIT_SSH_COMMAND can be used for this.
+
+ * A request to store an empty note via "git notes" meant to remove
+ note from the object but with --allow-empty we will store a
+ (surprise!) note that is empty.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ *
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.2
+----------------
+
+Unless otherwise noted, all the fixes since v2.2 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git checkout $treeish $path", when $path in the index and the
+ working tree already matched what is in $treeish at the $path,
+ still overwrote the $path unnecessarily.
+ (merge c5326bd jk/checkout-from-tree later to maint).
+
+ * "git config --get-color" did not parse its command line arguments
+ carefully.
+ (merge cb35722 jk/colors-fix later to maint).
+
+ * open() emulated on Windows platforms did not give EISDIR upon
+ an attempt to open a directory for writing.
+ (merge ba6fad0 js/windows-open-eisdir-error later to maint).
+
+ * A few code paths used abs() when they should have used labs() on
+ long integers.
+ (merge 83915ba rs/maint-config-use-labs later to maint).
+ (merge 31a8aa1 rs/receive-pack-use-labs later to maint).
+
+ * "gitweb" used to depend on a behaviour recent CGI.pm deprecated.
+ (merge 13dbf46 jk/gitweb-with-newer-cgi-multi-param later to maint).
+
+ * "git init" (hence "git clone") initialized the per-repository
+ configuration file .git/config with x-bit by mistake.
+ (merge 1f32ecf mh/config-flip-xbit-back-after-checking later to maint).
+
+ * Git 2.0 was supposed to make the "simple" mode for the default of
+ "git push", but it didn't.
+ (merge 00a6fa0 jk/push-simple later to maint).
+
+ * "Everyday" document had a broken link.
+ (merge 366c8d4 po/everyday-doc later to maint).
+
+ * A few test fixes.
+ (merge 880ef58 jk/no-perl-tests later to maint).
+
+ * The build procedure did not bother fixing perl and python scripts
+ when NO_PERL and NO_PYTHON build-time configuration changed.
+ (merge ca2051d jk/rebuild-perl-scripts-with-no-perl-seting-change later to maint).
differs substantially from the prior version, are all good things
to have.
-Make sure that you have tests for the bug you are fixing.
+Make sure that you have tests for the bug you are fixing. See
+t/README for guidance.
When adding a new feature, make sure that you have new tests to show
the feature triggers the new behaviour when it should, and to show the
When false, file names are handled fully transparent by Git,
which is backward compatible with older versions of Git.
+core.protectHFS::
+ If set to true, do not allow checkout of paths that would
+ be considered equivalent to `.git` on an HFS+ filesystem.
+ Defaults to `true` on Mac OS, and `false` elsewhere.
+
+core.protectNTFS::
+ If set to true, do not allow checkout of paths that would
+ cause problems with the NTFS filesystem, e.g. conflict with
+ 8.3 "short" names.
+ Defaults to `true` on Windows, and `false` elsewhere.
+
core.trustctime::
If false, the ctime differences between the index and the
working tree are ignored; useful when the inode change time
`blink` and `reverse`. The first color given is the foreground; the
second is the background. The position of the attribute, if any,
doesn't matter.
++
+Colors (foreground and background) may also be given as numbers between
+0 and 255; these use ANSI 256-color mode (but note that not all
+terminals may support this).
color.diff::
Whether to use ANSI escape sequences to add color to patches.
print a warning of such a push to stderr, but allow the push to
proceed. If set to false or "ignore", allow such pushes with no
message. Defaults to "refuse".
++
+Another option is "updateInstead" which will update the working
+directory (must be clean) if pushing into the current branch. This option is
+intended for synchronizing working directories when one side is not easily
+accessible via interactive ssh (e.g. a live web site, hence the requirement
+that the working directory be clean). This mode also comes in handy when
+developing inside a VM to test and fix code on different Operating Systems.
receive.denyNonFastForwards::
If set to true, git-receive-pack will deny a ref update which is
sendemail.smtpserveroption::
sendemail.smtpuser::
sendemail.thread::
+sendemail.transferencoding::
sendemail.validate::
See linkgit:git-send-email[1] for description.
--no-scissors::
Ignore scissors lines (see linkgit:git-mailinfo[1]).
+-m::
+--message-id::
+ Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
+ so that the Message-ID header is added to the commit message.
+ The `am.messageid` configuration variable can be used to specify
+ the default behaviour.
+
+--no-message-id::
+ Do not add the Message-ID header to the commit message.
+ `no-message-id` is useful to override `am.messageid`.
+
-q::
--quiet::
Be quiet. Only print error messages.
included. Later patterns within a file take precedence over earlier
ones.
+By default, tracked files are not shown at all since they are not
+subject to exclude rules; but see `--no-index'.
+
OPTIONS
-------
-q, --quiet::
-n::
Disable all charset re-coding of the metadata.
+-m::
+--message-id::
+ Copy the Message-ID header at the end of the commit message. This
+ is useful in order to associate commits with mailing list discussions.
+
--scissors::
Remove everything in body before a scissors line. A line that
mainly consists of scissors (either ">8" or "8<") and perforation
--------
[verse]
'git notes' [list [<object>]]
-'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
'git notes' copy [-f] ( --stdin | <from-object> <to-object> )
-'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' edit [<object>]
+'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' edit [--allow-empty] [<object>]
'git notes' show [<object>]
'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
'git notes' merge --commit [-v | -q]
Like '-C', but with '-c' the editor is invoked, so that
the user can further edit the note message.
+--allow-empty::
+ Allow an empty note object to be stored. The default behavior is
+ to automatically remove empty notes.
+
--ref <ref>::
Manipulate the notes tree in <ref>. This overrides
'GIT_NOTES_REF' and the "core.notesRef" configuration. The ref
------------
$ cc *.c
$ blob=$(git hash-object -w a.out)
-$ git notes --ref=built add -C "$blob" HEAD
+$ git notes --ref=built add --allow-empty -C "$blob" HEAD
------------
(You cannot simply use `git notes --ref=built add -F a.out HEAD`
arguments or `--all`, `--mirror`, `--tags` options, the command finds
the default `<refspec>` by consulting `remote.*.push` configuration,
and if it is not found, honors `push.default` configuration to decide
-what to push (See gitlink:git-config[1] for the meaning of `push.default`).
+what to push (See linkgit:git-config[1] for the meaning of `push.default`).
OPTIONS[[OPTIONS]]
Specify encoding of compose message. Default is the value of the
'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
+--transfer-encoding=(7bit|8bit|quoted-printable|base64)::
+ Specify the transfer encoding to be used to send the message over SMTP.
+ 7bit will fail upon encountering a non-ASCII message. quoted-printable
+ can be useful when the repository contains files that contain carriage
+ returns, but makes the raw patch email file (as saved from a MUA) much
+ harder to inspect manually. base64 is even more fool proof, but also
+ even more opaque. Default is the value of the 'sendemail.transferEncoding'
+ configuration value; if that is unspecified, git will use 8bit and not
+ add a Content-Transfer-Encoding header.
+
Sending
~~~~~~~
--------
[verse]
'git stripspace' [-s | --strip-comments] < input
+'git stripspace' [-c | --comment-lines] < input
DESCRIPTION
-----------
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v2.2.0/git.html[documentation for release 2.2]
+* link:v2.2.1/git.html[documentation for release 2.2.1]
* release notes for
+ link:RelNotes/2.2.1.txt[2.2.1],
link:RelNotes/2.2.0.txt[2.2].
-* link:v2.1.3/git.html[documentation for release 2.1.3]
+* link:v2.1.4/git.html[documentation for release 2.1.4]
* release notes for
+ link:RelNotes/2.1.4.txt[2.1.4],
link:RelNotes/2.1.3.txt[2.1.3],
link:RelNotes/2.1.2.txt[2.1.2],
link:RelNotes/2.1.1.txt[2.1.1],
link:RelNotes/2.1.0.txt[2.1].
-* link:v2.0.4/git.html[documentation for release 2.0.4]
+* link:v2.0.5/git.html[documentation for release 2.0.5]
* release notes for
+ link:RelNotes/2.0.5.txt[2.0.5],
link:RelNotes/2.0.4.txt[2.0.4],
link:RelNotes/2.0.3.txt[2.0.3],
link:RelNotes/2.0.2.txt[2.0.2],
link:RelNotes/2.0.1.txt[2.0.1],
link:RelNotes/2.0.0.txt[2.0.0].
-* link:v1.9.4/git.html[documentation for release 1.9.4]
+* link:v1.9.5/git.html[documentation for release 1.9.5]
* release notes for
+ link:RelNotes/1.9.5.txt[1.9.5],
link:RelNotes/1.9.4.txt[1.9.4],
link:RelNotes/1.9.3.txt[1.9.3],
link:RelNotes/1.9.2.txt[1.9.2],
link:RelNotes/1.9.1.txt[1.9.1],
link:RelNotes/1.9.0.txt[1.9.0].
-* link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
+* link:v1.8.5.6/git.html[documentation for release 1.8.5.6]
* release notes for
+ link:RelNotes/1.8.5.6.txt[1.8.5.6],
link:RelNotes/1.8.5.5.txt[1.8.5.5],
link:RelNotes/1.8.5.4.txt[1.8.5.4],
link:RelNotes/1.8.5.3.txt[1.8.5.3],
and the `core.editor` option in linkgit:git-config[1].
'GIT_SSH'::
- If this environment variable is set then 'git fetch'
- and 'git push' will use this command instead
- of 'ssh' when they need to connect to a remote system.
- The '$GIT_SSH' command will be given exactly two or
- four arguments: the 'username@host' (or just 'host')
- from the URL and the shell command to execute on that
- remote system, optionally preceded by '-p' (literally) and
- the 'port' from the URL when it specifies something other
- than the default SSH port.
+'GIT_SSH_COMMAND'::
+ If either of these environment variables is set then 'git fetch'
+ and 'git push' will use the specified command instead of 'ssh'
+ when they need to connect to a remote system.
+ The command will be given exactly two or four arguments: the
+ 'username@host' (or just 'host') from the URL and the shell
+ command to execute on that remote system, optionally preceded by
+ '-p' (literally) and the 'port' from the URL when it specifies
+ something other than the default SSH port.
+
-To pass options to the program that you want to list in GIT_SSH
-you will need to wrap the program and options into a shell script,
-then set GIT_SSH to refer to the shell script.
+`$GIT_SSH_COMMAND` takes precedence over `$GIT_SSH`, and is interpreted
+by the shell, which allows additional arguments to be included.
+`$GIT_SSH` on the other hand must be just the path to a program
+(which can be a wrapper shell script, if additional arguments are
+needed).
+
Usually it is easier to configure any desired options through your
personal `.ssh/config` file. Please consult your ssh documentation
and read the password from its STDOUT. See also the 'core.askpass'
option in linkgit:git-config[1].
+'GIT_TERMINAL_PROMPT'::
+ If this environment variable is set to `0`, git will not prompt
+ on the terminal (e.g., when asking for HTTP authentication).
+
'GIT_CONFIG_NOSYSTEM'::
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
For a `get` operation, the helper should produce a list of attributes
on stdout in the same format. A helper is free to produce a subset, or
even no values at all if it has nothing useful to provide. Any provided
-attributes will overwrite those already known about by Git.
+attributes will overwrite those already known about by Git. If a helper
+outputs a `quit` attribute with a value of `true` or `1`, no further
+helpers will be consulted, nor will the user be prompted (if no
+credential has been provided, the operation will then fail).
For a `store` or `erase` operation, the helper's output is ignored.
If it fails to perform the requested operation, it may complain to
`unsorted_string_list_has_string` and get it from the list using
`string_list_lookup` for sorted lists.
-. Can sort an unsorted list using `sort_string_list`.
+. Can sort an unsorted list using `string_list_sort`.
. Can remove duplicate items from a sorted list using
`string_list_remove_duplicates`.
ownership of a malloc()ed string to a `string_list` that has
`strdup_string` set.
-`sort_string_list`::
+`string_list_sort`::
Sort the list's entries by string value in `strcmp()` order.
# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
# the executable mode bit, but doesn't really do so.
#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values (e.g. z/OS defines I_SFMT to 0xFF000000 as opposed to the
+# usual 0xF000).
+#
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
#
# Define NO_UNIX_SOCKETS if your system does not offer unix sockets.
ifdef NO_TRUSTABLE_FILEMODE
BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
endif
+ifdef NEEDS_MODE_TRANSLATION
+ COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
+ COMPAT_OBJS += compat/stat.o
+endif
ifdef NO_IPV6
BASIC_CFLAGS += -DNO_IPV6
endif
fi
-$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES
+$(SCRIPT_SH_GEN) : % : %.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
$(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
-DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" $< -o $@
+# This makes sure we depend on the NO_PERL setting itself.
+$(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS
+
ifndef NO_PERL
-$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
+$(SCRIPT_PERL_GEN): perl/perl.mak
perl/perl.mak: perl/PM.stamp
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ)
-$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE
+$(SCRIPT_PERL_GEN): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
chmod +x $@+ && \
mv $@+ $@
else # NO_PERL
-$(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
+$(SCRIPT_PERL_GEN) git-instaweb: % : unimplemented.sh
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \
mv $@+ $@
endif # NO_PERL
+# This makes sure we depend on the NO_PYTHON setting itself.
+$(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS
+
ifndef NO_PYTHON
$(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
$(SCRIPT_PYTHON_GEN): % : %.py
-Documentation/RelNotes/2.2.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.3.0.txt
\ No newline at end of file
return write_entry(args, sha1, path.buf, path.len, mode);
}
+static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base,
+ const char *filename, unsigned mode, int stage,
+ void *context)
+{
+ return write_archive_entry(sha1, base->buf, base->len,
+ filename, mode, stage, context);
+}
+
static void queue_directory(const unsigned char *sha1,
- const char *base, int baselen, const char *filename,
+ struct strbuf *base, const char *filename,
unsigned mode, int stage, struct archiver_context *c)
{
struct directory *d;
- d = xmallocz(sizeof(*d) + baselen + 1 + strlen(filename));
+ d = xmallocz(sizeof(*d) + base->len + 1 + strlen(filename));
d->up = c->bottom;
- d->baselen = baselen;
+ d->baselen = base->len;
d->mode = mode;
d->stage = stage;
c->bottom = d;
- d->len = sprintf(d->path, "%.*s%s/", baselen, base, filename);
+ d->len = sprintf(d->path, "%.*s%s/", (int)base->len, base->buf, filename);
hashcpy(d->sha1, sha1);
}
}
static int queue_or_write_archive_entry(const unsigned char *sha1,
- const char *base, int baselen, const char *filename,
+ struct strbuf *base, const char *filename,
unsigned mode, int stage, void *context)
{
struct archiver_context *c = context;
while (c->bottom &&
- !(baselen >= c->bottom->len &&
- !strncmp(base, c->bottom->path, c->bottom->len))) {
+ !(base->len >= c->bottom->len &&
+ !strncmp(base->buf, c->bottom->path, c->bottom->len))) {
struct directory *next = c->bottom->up;
free(c->bottom);
c->bottom = next;
}
if (S_ISDIR(mode)) {
- queue_directory(sha1, base, baselen, filename,
+ queue_directory(sha1, base, filename,
mode, stage, c);
return READ_TREE_RECURSIVE;
}
if (write_directory(c))
return -1;
- return write_archive_entry(sha1, base, baselen, filename, mode,
+ return write_archive_entry(sha1, base->buf, base->len, filename, mode,
stage, context);
}
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
args->pathspec.has_wildcard ?
queue_or_write_archive_entry :
- write_archive_entry,
+ write_archive_entry_buf,
&context);
if (err == READ_TREE_RECURSIVE)
err = 0;
return NULL;
}
-static int reject_entry(const unsigned char *sha1, const char *base,
- int baselen, const char *filename, unsigned mode,
+static int reject_entry(const unsigned char *sha1, struct strbuf *base,
+ const char *filename, unsigned mode,
int stage, void *context)
{
int ret = -1;
if (S_ISDIR(mode)) {
struct strbuf sb = STRBUF_INIT;
- strbuf_addstr(&sb, base);
+ strbuf_addbuf(&sb, base);
strbuf_addstr(&sb, filename);
if (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))
ret = READ_TREE_RECURSIVE;
for (i = 0; i < dir->ignored_nr; i++)
fprintf(stderr, "%s\n", dir->ignored[i]->name);
fprintf(stderr, _("Use -f if you really want to add them.\n"));
- die(_("no files added"));
+ exit_status = 1;
}
for (i = 0; i < dir->nr; i++)
if (!preimage_sha1_in_gitlink_patch(patch, sha1))
; /* ok, the textual part looks sane */
else
- die("sha1 information is lacking or useless for submoule %s",
+ die("sha1 information is lacking or useless for submodule %s",
name);
} else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
; /* ok */
if (cpath.nr) {
struct string_list_item *item;
- sort_string_list(&cpath);
+ string_list_sort(&cpath);
for_each_string_list_item(item, &cpath)
fprintf(stderr, "U %s\n", item->string);
string_list_clear(&cpath, 0);
}
-static int update_some(const unsigned char *sha1, const char *base, int baselen,
+static int update_some(const unsigned char *sha1, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
int len;
struct cache_entry *ce;
+ int pos;
if (S_ISDIR(mode))
return READ_TREE_RECURSIVE;
- len = baselen + strlen(pathname);
+ len = base->len + strlen(pathname);
ce = xcalloc(1, cache_entry_size(len));
hashcpy(ce->sha1, sha1);
- memcpy(ce->name, base, baselen);
- memcpy(ce->name + baselen, pathname, len - baselen);
+ memcpy(ce->name, base->buf, base->len);
+ memcpy(ce->name + base->len, pathname, len - base->len);
ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
+
+ /*
+ * If the entry is the same as the current index, we can leave the old
+ * entry in place. Whether it is UPTODATE or not, checkout_entry will
+ * do the right thing.
+ */
+ pos = cache_name_pos(ce->name, ce->ce_namelen);
+ if (pos >= 0) {
+ struct cache_entry *old = active_cache[pos];
+ if (ce->ce_mode == old->ce_mode &&
+ !hashcmp(ce->sha1, old->sha1)) {
+ old->ce_flags |= CE_UPDATE;
+ free(ce);
+ return 0;
+ }
+ }
+
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
return 0;
}
if (clean_message_contents)
stripspace(&sb, 0);
- if (signoff) {
- /*
- * See if we have a Conflicts: block at the end. If yes, count
- * its size, so we can ignore it.
- */
- int ignore_footer = 0;
- int i, eol, previous = 0;
- const char *nl;
-
- for (i = 0; i < sb.len; i++) {
- nl = memchr(sb.buf + i, '\n', sb.len - i);
- if (nl)
- eol = nl - sb.buf;
- else
- eol = sb.len;
- if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
- ignore_footer = sb.len - previous;
- break;
- }
- while (i < eol)
- i++;
- previous = eol;
- }
-
- append_signoff(&sb, ignore_footer, 0);
- }
+ if (signoff)
+ append_signoff(&sb, ignore_non_trailer(&sb), 0);
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
- OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")),
- OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")),
+ OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
+ OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
OPT_GROUP(N_("Type")),
OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL),
OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
return 0;
}
-static void get_color(const char *def_color)
+static void get_color(const char *var, const char *def_color)
{
+ get_color_slot = var;
get_color_found = 0;
parsed_color[0] = '\0';
git_config_with_options(git_get_color_config, NULL,
return 0;
}
-static int get_colorbool(int print)
+static int get_colorbool(const char *var, int print)
{
+ get_colorbool_slot = var;
get_colorbool_found = -1;
get_diff_color_found = -1;
get_color_ui_found = -1;
usage_with_options(builtin_config_usage, builtin_config_options);
}
- if (get_color_slot)
- actions |= ACTION_GET_COLOR;
- if (get_colorbool_slot)
- actions |= ACTION_GET_COLORBOOL;
-
- if ((get_color_slot || get_colorbool_slot) && types) {
+ if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && types) {
error("--get-color and variable type are incoherent");
usage_with_options(builtin_config_usage, builtin_config_options);
}
}
}
else if (actions == ACTION_EDIT) {
- const char *config_file = given_config_source.file ?
- given_config_source.file : git_path("config");
+ char *config_file;
+
check_argc(argc, 0, 0);
if (!given_config_source.file && nongit)
die("not in a git directory");
if (given_config_source.blob)
die("editing blobs is not supported");
git_config(git_default_config, NULL);
+ config_file = xstrdup(given_config_source.file ?
+ given_config_source.file : git_path("config"));
if (use_global_config) {
int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd) {
die_errno(_("cannot create configuration file %s"), config_file);
}
launch_editor(config_file, NULL, NULL);
+ free(config_file);
}
else if (actions == ACTION_SET) {
int ret;
die("No such section!");
}
else if (actions == ACTION_GET_COLOR) {
- get_color(argv[0]);
+ check_argc(argc, 1, 2);
+ get_color(argv[0], argv[1]);
}
else if (actions == ACTION_GET_COLORBOOL) {
- if (argc == 1)
- color_stdout_is_tty = git_config_bool("command line", argv[0]);
- return get_colorbool(argc != 0);
+ check_argc(argc, 1, 2);
+ if (argc == 2)
+ color_stdout_is_tty = git_config_bool("command line", argv[1]);
+ return get_colorbool(argv[0], argc == 2);
}
return 0;
OPT_BIT(0 , "python", "e_style,
N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", "e_style,
- N_("quote placeholders suitably for tcl"), QUOTE_TCL),
+ N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
{
struct strbuf new_path = STRBUF_INIT;
const char *old_path = getenv("MANPATH");
+ char *git_man_path = system_path(GIT_MAN_PATH);
/* We should always put ':' after our path. If there is no
* old_path, the ':' at the end will let 'man' to try
* system-wide paths after ours to find the manual page. If
* there is old_path, we need ':' as delimiter. */
- strbuf_addstr(&new_path, system_path(GIT_MAN_PATH));
+ strbuf_addstr(&new_path, git_man_path);
strbuf_addch(&new_path, ':');
if (old_path)
strbuf_addstr(&new_path, old_path);
+ free(git_man_path);
setenv("MANPATH", new_path.buf, 1);
strbuf_release(&new_path);
static void get_html_page_path(struct strbuf *page_path, const char *page)
{
struct stat st;
+ char *to_free = NULL;
+
if (!html_path)
- html_path = system_path(GIT_HTML_PATH);
+ html_path = to_free = system_path(GIT_HTML_PATH);
/* Check that we have a git documentation directory. */
if (!strstr(html_path, "://")) {
strbuf_init(page_path, 0);
strbuf_addf(page_path, "%s/%s.html", html_path, page);
+ free(to_free);
}
/*
DIR *dir;
const char *git_dir = get_git_dir();
int len = strlen(git_dir);
+ char *to_free = NULL;
if (!template_dir)
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
if (!template_dir)
template_dir = init_db_template_dir;
if (!template_dir)
- template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
- if (!template_dir[0])
+ template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
+ if (!template_dir[0]) {
+ free(to_free);
return;
+ }
template_len = strlen(template_dir);
if (PATH_MAX <= (template_len+strlen("/config")))
die(_("insanely long template path %s"), template_dir);
dir = opendir(template_path);
if (!dir) {
warning(_("templates not found %s"), template_dir);
- return;
+ goto free_return;
}
/* Make sure that template is from the correct vintage */
"a wrong format version %d from '%s'"),
repository_format_version,
template_dir);
- closedir(dir);
- return;
+ goto close_free_return;
}
memcpy(path, git_dir, len);
copy_templates_1(path, len,
template_path, template_len,
dir);
+close_free_return:
closedir(dir);
+free_return:
+ free(to_free);
}
static int git_init_db_config(const char *k, const char *v, void *cb)
struct stat st2;
filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
!lstat(path, &st2) &&
- st1.st_mode != st2.st_mode);
+ st1.st_mode != st2.st_mode &&
+ !chmod(path, st1.st_mode));
+ if (filemode && !reinit && (st1.st_mode & S_IXUSR))
+ filemode = 0;
}
git_config_set("core.filemode", filemode ? "true" : "false");
}
static int show_tree_object(const unsigned char *sha1,
- const char *base, int baselen,
+ struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
}
}
-static int show_tree(const unsigned char *sha1, const char *base, int baselen,
+static int show_tree(const unsigned char *sha1, struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
int retval = 0;
+ int baselen;
const char *type = blob_type;
if (S_ISGITLINK(mode)) {
*/
type = commit_type;
} else if (S_ISDIR(mode)) {
- if (show_recursive(base, baselen, pathname)) {
+ if (show_recursive(base->buf, base->len, pathname)) {
retval = READ_TREE_RECURSIVE;
if (!(ls_options & LS_SHOW_TREES))
return retval;
else if (ls_options & LS_TREE_ONLY)
return 0;
- if (chomp_prefix &&
- (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))
- return 0;
-
if (!(ls_options & LS_NAME_ONLY)) {
if (ls_options & LS_SHOW_SIZE) {
char size_text[24];
printf("%06o %s %s\t", mode, type,
find_unique_abbrev(sha1, abbrev));
}
- write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
- pathname, stdout, line_termination);
+ baselen = base->len;
+ strbuf_addstr(base, pathname);
+ write_name_quoted_relative(base->buf,
+ chomp_prefix ? ls_tree_prefix : NULL,
+ stdout, line_termination);
+ strbuf_setlen(base, baselen);
return retval;
}
* cannot be lifted until it is converted to use
* match_pathspec() or tree_entry_interesting()
*/
- parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
+ parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE,
PATHSPEC_PREFER_CWD,
prefix, argv + 1);
for (i = 0; i < pathspec.nr; i++)
static struct strbuf line = STRBUF_INIT;
static struct strbuf name = STRBUF_INIT;
static struct strbuf email = STRBUF_INIT;
+static char *message_id;
static enum {
TE_DONTCARE, TE_QP, TE_BASE64
static int patch_lines;
static struct strbuf **p_hdr_data, **s_hdr_data;
static int use_scissors;
+static int add_message_id;
static int use_inbody_headers = 1;
#define MAX_HDR_PARSED 10
}
}
+static void handle_message_id(const struct strbuf *line)
+{
+ if (add_message_id)
+ message_id = strdup(line->buf);
+}
+
static void handle_content_transfer_encoding(const struct strbuf *line)
{
if (strcasestr(line->buf, "base64"))
ret = 1;
goto check_header_out;
}
+ if (cmp_header(line, "Message-Id")) {
+ len = strlen("Message-Id: ");
+ strbuf_add(&sb, line->buf + len, line->len - len);
+ decode_header(&sb);
+ handle_message_id(&sb);
+ ret = 1;
+ goto check_header_out;
+ }
/* for inbody stuff */
if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
}
if (patchbreak(line)) {
+ if (message_id)
+ fprintf(cmitmsg, "Message-Id: %s\n", message_id);
fclose(cmitmsg);
cmitmsg = NULL;
return 1;
}
static const char mailinfo_usage[] =
- "git mailinfo [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
+ "git mailinfo [-k|-b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
{
keep_subject = 1;
else if (!strcmp(argv[1], "-b"))
keep_non_patch_brackets_in_subject = 1;
+ else if (!strcmp(argv[1], "-m") || !strcmp(argv[1], "--message-id"))
+ add_message_id = 1;
else if (!strcmp(argv[1], "-u"))
metainfo_charset = def_charset;
else if (!strcmp(argv[1], "-n"))
#include "remote.h"
#include "fmt-merge-msg.h"
#include "gpg-interface.h"
+#include "sequencer.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
return 0;
}
-static int suggest_conflicts(int renormalizing)
+static int suggest_conflicts(void)
{
const char *filename;
FILE *fp;
- int pos;
+ struct strbuf msgbuf = STRBUF_INIT;
filename = git_path("MERGE_MSG");
fp = fopen(filename, "a");
if (!fp)
die_errno(_("Could not open '%s' for writing"), filename);
- fprintf(fp, "\nConflicts:\n");
- for (pos = 0; pos < active_nr; pos++) {
- const struct cache_entry *ce = active_cache[pos];
-
- if (ce_stage(ce)) {
- fprintf(fp, "\t%s\n", ce->name);
- while (pos + 1 < active_nr &&
- !strcmp(ce->name,
- active_cache[pos + 1]->name))
- pos++;
- }
- }
+
+ append_conflicts_hint(&msgbuf);
+ fputs(msgbuf.buf, fp);
fclose(fp);
rerere(allow_rerere_auto);
printf(_("Automatic merge failed; "
fprintf(stderr, _("Automatic merge went well; "
"stopped before committing as requested\n"));
else
- ret = suggest_conflicts(option_renormalize);
+ ret = suggest_conflicts();
done:
free(branch_to_free);
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes_ref>] [list [<object>]]"),
- N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes_ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
- N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
- N_("git notes [--ref <notes_ref>] edit [<object>]"),
+ N_("git notes [--ref <notes_ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes_ref>] edit [--allow-empty] [<object>]"),
N_("git notes [--ref <notes_ref>] show [<object>]"),
N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
N_("git notes merge --commit [-v | -q]"),
static const char note_template[] =
"\nWrite/edit the notes for the following object:\n";
-struct msg_arg {
+struct note_data {
int given;
int use_editor;
+ char *edit_path;
struct strbuf buf;
};
+static void free_note_data(struct note_data *d)
+{
+ if (d->edit_path) {
+ unlink_or_warn(d->edit_path);
+ free(d->edit_path);
+ }
+ strbuf_release(&d->buf);
+}
+
static int list_each_note(const unsigned char *object_sha1,
const unsigned char *note_sha1, char *note_path,
void *cb_data)
return 0;
}
-static void write_note_data(int fd, const unsigned char *sha1)
+static void copy_obj_to_fd(int fd, const unsigned char *sha1)
{
unsigned long size;
enum object_type type;
sha1_to_hex(object));
}
-static void create_note(const unsigned char *object, struct msg_arg *msg,
- int append_only, const unsigned char *prev,
- unsigned char *result)
+static void prepare_note_data(const unsigned char *object, struct note_data *d,
+ const unsigned char *old_note)
{
- char *path = NULL;
-
- if (msg->use_editor || !msg->given) {
+ if (d->use_editor || !d->given) {
int fd;
struct strbuf buf = STRBUF_INIT;
/* write the template message before editing: */
- path = git_pathdup("NOTES_EDITMSG");
- fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ d->edit_path = git_pathdup("NOTES_EDITMSG");
+ fd = open(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
- die_errno(_("could not create file '%s'"), path);
+ die_errno(_("could not create file '%s'"), d->edit_path);
- if (msg->given)
- write_or_die(fd, msg->buf.buf, msg->buf.len);
- else if (prev && !append_only)
- write_note_data(fd, prev);
+ if (d->given)
+ write_or_die(fd, d->buf.buf, d->buf.len);
+ else if (old_note)
+ copy_obj_to_fd(fd, old_note);
strbuf_addch(&buf, '\n');
strbuf_add_commented_lines(&buf, note_template, strlen(note_template));
close(fd);
strbuf_release(&buf);
- strbuf_reset(&(msg->buf));
-
- if (launch_editor(path, &(msg->buf), NULL)) {
- die(_("Please supply the note contents using either -m" \
- " or -F option"));
- }
- stripspace(&(msg->buf), 1);
- }
-
- if (prev && append_only) {
- /* Append buf to previous note contents */
- unsigned long size;
- enum object_type type;
- char *prev_buf = read_sha1_file(prev, &type, &size);
+ strbuf_reset(&d->buf);
- strbuf_grow(&(msg->buf), size + 1);
- if (msg->buf.len && prev_buf && size)
- strbuf_insert(&(msg->buf), 0, "\n", 1);
- if (prev_buf && size)
- strbuf_insert(&(msg->buf), 0, prev_buf, size);
- free(prev_buf);
- }
-
- if (!msg->buf.len) {
- fprintf(stderr, _("Removing note for object %s\n"),
- sha1_to_hex(object));
- hashclr(result);
- } else {
- if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
- error(_("unable to write note object"));
- if (path)
- error(_("The note contents have been left in %s"),
- path);
- exit(128);
+ if (launch_editor(d->edit_path, &d->buf, NULL)) {
+ die(_("Please supply the note contents using either -m or -F option"));
}
+ stripspace(&d->buf, 1);
}
+}
- if (path) {
- unlink_or_warn(path);
- free(path);
+static void write_note_data(struct note_data *d, unsigned char *sha1)
+{
+ if (write_sha1_file(d->buf.buf, d->buf.len, blob_type, sha1)) {
+ error(_("unable to write note object"));
+ if (d->edit_path)
+ error(_("The note contents have been left in %s"),
+ d->edit_path);
+ exit(128);
}
}
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
{
- struct msg_arg *msg = opt->value;
+ struct note_data *d = opt->value;
- strbuf_grow(&(msg->buf), strlen(arg) + 2);
- if (msg->buf.len)
- strbuf_addch(&(msg->buf), '\n');
- strbuf_addstr(&(msg->buf), arg);
- stripspace(&(msg->buf), 0);
+ strbuf_grow(&d->buf, strlen(arg) + 2);
+ if (d->buf.len)
+ strbuf_addch(&d->buf, '\n');
+ strbuf_addstr(&d->buf, arg);
+ stripspace(&d->buf, 0);
- msg->given = 1;
+ d->given = 1;
return 0;
}
static int parse_file_arg(const struct option *opt, const char *arg, int unset)
{
- struct msg_arg *msg = opt->value;
+ struct note_data *d = opt->value;
- if (msg->buf.len)
- strbuf_addch(&(msg->buf), '\n');
+ if (d->buf.len)
+ strbuf_addch(&d->buf, '\n');
if (!strcmp(arg, "-")) {
- if (strbuf_read(&(msg->buf), 0, 1024) < 0)
+ if (strbuf_read(&d->buf, 0, 1024) < 0)
die_errno(_("cannot read '%s'"), arg);
- } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0)
+ } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
die_errno(_("could not open or read '%s'"), arg);
- stripspace(&(msg->buf), 0);
+ stripspace(&d->buf, 0);
- msg->given = 1;
+ d->given = 1;
return 0;
}
static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
{
- struct msg_arg *msg = opt->value;
+ struct note_data *d = opt->value;
char *buf;
unsigned char object[20];
enum object_type type;
unsigned long len;
- if (msg->buf.len)
- strbuf_addch(&(msg->buf), '\n');
+ if (d->buf.len)
+ strbuf_addch(&d->buf, '\n');
if (get_sha1(arg, object))
die(_("Failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = read_sha1_file(object, &type, &len)) || !len) {
+ if (!(buf = read_sha1_file(object, &type, &len))) {
free(buf);
die(_("Failed to read object '%s'."), arg);
}
free(buf);
die(_("Cannot read note data from non-blob object '%s'."), arg);
}
- strbuf_add(&(msg->buf), buf, len);
+ strbuf_add(&d->buf, buf, len);
free(buf);
- msg->given = 1;
+ d->given = 1;
return 0;
}
static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
{
- struct msg_arg *msg = opt->value;
- msg->use_editor = 1;
+ struct note_data *d = opt->value;
+ d->use_editor = 1;
return parse_reuse_arg(opt, arg, unset);
}
static int add(int argc, const char **argv, const char *prefix)
{
- int retval = 0, force = 0;
+ int force = 0, allow_empty = 0;
const char *object_ref;
struct notes_tree *t;
unsigned char object[20], new_note[20];
- char logmsg[100];
const unsigned char *note;
- struct msg_arg msg = { 0, 0, STRBUF_INIT };
+ struct note_data d = { 0, 0, NULL, STRBUF_INIT };
struct option options[] = {
- { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ { OPTION_CALLBACK, 'm', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
parse_msg_arg},
- { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+ { OPTION_CALLBACK, 'F', "file", &d, N_("file"),
N_("note contents in a file"), PARSE_OPT_NONEG,
parse_file_arg},
- { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+ { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"),
N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg},
- { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+ { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg},
+ OPT_BOOL(0, "allow-empty", &allow_empty,
+ N_("allow storing empty note")),
OPT__FORCE(&force, N_("replace existing notes")),
OPT_END()
};
if (note) {
if (!force) {
- if (!msg.given) {
- /*
- * Redirect to "edit" subcommand.
- *
- * We only end up here if none of -m/-F/-c/-C
- * or -f are given. The original args are
- * therefore still in argv[0-1].
- */
- argv[0] = "edit";
- free_notes(t);
- return append_edit(argc, argv, prefix);
+ free_notes(t);
+ if (d.given) {
+ free_note_data(&d);
+ return error(_("Cannot add notes. "
+ "Found existing notes for object %s. "
+ "Use '-f' to overwrite existing notes"),
+ sha1_to_hex(object));
}
- retval = error(_("Cannot add notes. Found existing notes "
- "for object %s. Use '-f' to overwrite "
- "existing notes"), sha1_to_hex(object));
- goto out;
+ /*
+ * Redirect to "edit" subcommand.
+ *
+ * We only end up here if none of -m/-F/-c/-C or -f are
+ * given. The original args are therefore still in
+ * argv[0-1].
+ */
+ argv[0] = "edit";
+ return append_edit(argc, argv, prefix);
}
fprintf(stderr, _("Overwriting existing notes for object %s\n"),
sha1_to_hex(object));
}
- create_note(object, &msg, 0, note, new_note);
-
- if (is_null_sha1(new_note))
+ prepare_note_data(object, &d, note);
+ if (d.buf.len || allow_empty) {
+ write_note_data(&d, new_note);
+ if (add_note(t, object, new_note, combine_notes_overwrite))
+ die("BUG: combine_notes_overwrite failed");
+ commit_notes(t, "Notes added by 'git notes add'");
+ } else {
+ fprintf(stderr, _("Removing note for object %s\n"),
+ sha1_to_hex(object));
remove_note(t, object);
- else if (add_note(t, object, new_note, combine_notes_overwrite))
- die("BUG: combine_notes_overwrite failed");
+ commit_notes(t, "Notes removed by 'git notes add'");
+ }
- snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
- is_null_sha1(new_note) ? "removed" : "added", "add");
- commit_notes(t, logmsg);
-out:
+ free_note_data(&d);
free_notes(t);
- strbuf_release(&(msg.buf));
- return retval;
+ return 0;
}
static int copy(int argc, const char **argv, const char *prefix)
static int append_edit(int argc, const char **argv, const char *prefix)
{
+ int allow_empty = 0;
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 note_data d = { 0, 0, NULL, STRBUF_INIT };
struct option options[] = {
- { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ { OPTION_CALLBACK, 'm', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
parse_msg_arg},
- { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+ { OPTION_CALLBACK, 'F', "file", &d, N_("file"),
N_("note contents in a file"), PARSE_OPT_NONEG,
parse_file_arg},
- { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+ { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"),
N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg},
- { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+ { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg},
+ OPT_BOOL(0, "allow-empty", &allow_empty,
+ N_("allow storing empty note")),
OPT_END()
};
int edit = !strcmp(argv[0], "edit");
usage_with_options(usage, options);
}
- if (msg.given && edit)
+ if (d.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"));
t = init_notes_check(argv[0]);
note = get_note(t, object);
- create_note(object, &msg, !edit, note, new_note);
+ prepare_note_data(object, &d, edit ? note : NULL);
- if (is_null_sha1(new_note))
- remove_note(t, object);
- else if (add_note(t, object, new_note, combine_notes_overwrite))
- die("BUG: combine_notes_overwrite failed");
+ if (note && !edit) {
+ /* Append buf to previous note contents */
+ unsigned long size;
+ enum object_type type;
+ char *prev_buf = read_sha1_file(note, &type, &size);
+
+ strbuf_grow(&d.buf, size + 1);
+ if (d.buf.len && prev_buf && size)
+ strbuf_insert(&d.buf, 0, "\n", 1);
+ if (prev_buf && size)
+ strbuf_insert(&d.buf, 0, prev_buf, size);
+ free(prev_buf);
+ }
- snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
- is_null_sha1(new_note) ? "removed" : "added", argv[0]);
+ if (d.buf.len || allow_empty) {
+ write_note_data(&d, new_note);
+ if (add_note(t, object, new_note, combine_notes_overwrite))
+ die("BUG: combine_notes_overwrite failed");
+ snprintf(logmsg, sizeof(logmsg), "Notes added by 'git notes %s'",
+ argv[0]);
+ } else {
+ fprintf(stderr, _("Removing note for object %s\n"),
+ sha1_to_hex(object));
+ remove_note(t, object);
+ snprintf(logmsg, sizeof(logmsg), "Notes removed by 'git notes %s'",
+ argv[0]);
+ }
commit_notes(t, logmsg);
+
+ free_note_data(&d);
free_notes(t);
- strbuf_release(&(msg.buf));
return 0;
}
" git push %s HEAD:<name-of-remote-branch>\n");
static void setup_push_upstream(struct remote *remote, struct branch *branch,
- int triangular)
+ int triangular, int simple)
{
struct strbuf refspec = STRBUF_INIT;
"to update which remote branch."),
remote->name, branch->name);
- if (push_default == PUSH_DEFAULT_SIMPLE) {
+ if (simple) {
/* Additional safety */
if (strcmp(branch->refname, branch->merge[0]->src))
die_push_simple(branch, remote);
if (triangular)
setup_push_current(remote, branch);
else
- setup_push_upstream(remote, branch, triangular);
+ setup_push_upstream(remote, branch, triangular, 1);
break;
case PUSH_DEFAULT_UPSTREAM:
- setup_push_upstream(remote, branch, triangular);
+ setup_push_upstream(remote, branch, triangular, 0);
break;
case PUSH_DEFAULT_CURRENT:
0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option },
- { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"),
+ { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check|on-demand",
N_("control recursive pushing of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOL( 0 , "thin", &thin, N_("use thin pack")),
DENY_UNCONFIGURED,
DENY_IGNORE,
DENY_WARN,
- DENY_REFUSE
+ DENY_REFUSE,
+ DENY_UPDATE_INSTEAD
};
static int deny_deletes;
return DENY_WARN;
if (!strcasecmp(value, "refuse"))
return DENY_REFUSE;
+ if (!strcasecmp(value, "updateinstead"))
+ return DENY_UPDATE_INSTEAD;
}
if (git_config_bool(var, value))
return DENY_REFUSE;
nonce_stamp_slop = (long)ostamp - (long)stamp;
if (nonce_stamp_slop_limit &&
- abs(nonce_stamp_slop) <= nonce_stamp_slop_limit) {
+ labs(nonce_stamp_slop) <= nonce_stamp_slop_limit) {
/*
* Pretend as if the received nonce (which passes the
* HMAC check, so it is not a forged by third-party)
return 0;
}
+static const char *update_worktree(unsigned char *sha1)
+{
+ const char *update_refresh[] = {
+ "update-index", "-q", "--ignore-submodules", "--refresh", NULL
+ };
+ const char *diff_files[] = {
+ "diff-files", "--quiet", "--ignore-submodules", "--", NULL
+ };
+ const char *diff_index[] = {
+ "diff-index", "--quiet", "--cached", "--ignore-submodules",
+ "HEAD", "--", NULL
+ };
+ const char *read_tree[] = {
+ "read-tree", "-u", "-m", NULL, NULL
+ };
+ const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
+ struct argv_array env = ARGV_ARRAY_INIT;
+ struct child_process child = CHILD_PROCESS_INIT;
+
+ if (is_bare_repository())
+ return "denyCurrentBranch = updateInstead needs a worktree";
+
+ argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+
+ child.argv = update_refresh;
+ child.env = env.argv;
+ child.dir = work_tree;
+ child.no_stdin = 1;
+ child.stdout_to_stderr = 1;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Up-to-date check failed";
+ }
+
+ /* run_command() does not clean up completely; reinitialize */
+ child_process_init(&child);
+ child.argv = diff_files;
+ child.env = env.argv;
+ child.dir = work_tree;
+ child.no_stdin = 1;
+ child.stdout_to_stderr = 1;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Working directory has unstaged changes";
+ }
+
+ child_process_init(&child);
+ child.argv = diff_index;
+ child.env = env.argv;
+ child.no_stdin = 1;
+ child.no_stdout = 1;
+ child.stdout_to_stderr = 0;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Working directory has staged changes";
+ }
+
+ read_tree[3] = sha1_to_hex(sha1);
+ child_process_init(&child);
+ child.argv = read_tree;
+ child.env = env.argv;
+ child.dir = work_tree;
+ child.no_stdin = 1;
+ child.no_stdout = 1;
+ child.stdout_to_stderr = 0;
+ child.git_cmd = 1;
+ if (run_command(&child)) {
+ argv_array_clear(&env);
+ return "Could not update working tree to new HEAD";
+ }
+
+ argv_array_clear(&env);
+ return NULL;
+}
+
static const char *update(struct command *cmd, struct shallow_info *si)
{
const char *name = cmd->ref_name;
struct strbuf namespaced_name_buf = STRBUF_INIT;
- const char *namespaced_name;
+ const char *namespaced_name, *ret;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
if (deny_current_branch == DENY_UNCONFIGURED)
refuse_unconfigured_deny();
return "branch is currently checked out";
+ case DENY_UPDATE_INSTEAD:
+ ret = update_worktree(new_sha1);
+ if (ret)
+ return ret;
+ break;
}
}
break;
case DENY_REFUSE:
case DENY_UNCONFIGURED:
+ case DENY_UPDATE_INSTEAD:
if (deny_delete_current == DENY_UNCONFIGURED)
refuse_unconfigured_deny_delete_current();
rp_error("refusing to delete the current branch: %s", name);
return "deletion of the current branch prohibited";
+ default:
+ return "Invalid denyDeleteCurrent setting";
}
}
}
string_list_append(&ref_list, cmd->ref_name);
item->util = (void *)cmd;
}
- sort_string_list(&ref_list);
+ string_list_sort(&ref_list);
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
free_refs(stale_refs);
free_refs(fetch_map);
- sort_string_list(&states->new);
- sort_string_list(&states->tracked);
- sort_string_list(&states->stale);
+ string_list_sort(&states->new);
+ string_list_sort(&states->tracked);
+ string_list_sort(&states->stale);
return 0;
}
static int remove_branches(struct string_list *branches)
{
struct strbuf err = STRBUF_INIT;
- const char **branch_names;
int i, result = 0;
- branch_names = xmalloc(branches->nr * sizeof(*branch_names));
- for (i = 0; i < branches->nr; i++)
- branch_names[i] = branches->items[i].string;
- if (repack_without_refs(branch_names, branches->nr, &err))
+ if (repack_without_refs(branches, &err))
result |= error("%s", err.buf);
strbuf_release(&err);
- free(branch_names);
for (i = 0; i < branches->nr; i++) {
struct string_list_item *item = branches->items + i;
get_push_ref_states(remote_refs, states);
} else {
for_each_ref(append_ref_to_tracked_list, states);
- sort_string_list(&states->tracked);
+ string_list_sort(&states->tracked);
get_push_ref_states_noquery(states);
}
if (!result) {
int i;
- sort_string_list(&list);
+ string_list_sort(&list);
for (i = 0; i < list.nr; i++) {
struct string_list_item *item = list.items + i;
if (verbose)
static int prune_remote(const char *remote, int dry_run)
{
- int result = 0, i;
+ int result = 0;
struct ref_states states;
- struct string_list delete_refs_list = STRING_LIST_INIT_NODUP;
- const char **delete_refs;
+ struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
const char *dangling_msg = dry_run
? _(" %s will become dangling!")
: _(" %s has become dangling!");
memset(&states, 0, sizeof(states));
get_remote_ref_states(remote, &states, GET_REF_STATES);
- if (states.stale.nr) {
- printf_ln(_("Pruning %s"), remote);
- printf_ln(_("URL: %s"),
- states.remote->url_nr
- ? states.remote->url[0]
- : _("(no URL)"));
-
- delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs));
- for (i = 0; i < states.stale.nr; i++)
- delete_refs[i] = states.stale.items[i].util;
- if (!dry_run) {
- struct strbuf err = STRBUF_INIT;
- if (repack_without_refs(delete_refs, states.stale.nr,
- &err))
- result |= error("%s", err.buf);
- strbuf_release(&err);
- }
- free(delete_refs);
+ if (!states.stale.nr) {
+ free_remote_ref_states(&states);
+ return 0;
}
- for (i = 0; i < states.stale.nr; i++) {
- const char *refname = states.stale.items[i].util;
+ printf_ln(_("Pruning %s"), remote);
+ printf_ln(_("URL: %s"),
+ states.remote->url_nr
+ ? states.remote->url[0]
+ : _("(no URL)"));
+
+ for_each_string_list_item(item, &states.stale)
+ string_list_append(&refs_to_prune, item->util);
+ string_list_sort(&refs_to_prune);
+
+ if (!dry_run) {
+ struct strbuf err = STRBUF_INIT;
+ if (repack_without_refs(&refs_to_prune, &err))
+ result |= error("%s", err.buf);
+ strbuf_release(&err);
+ }
- string_list_insert(&delete_refs_list, refname);
+ for_each_string_list_item(item, &states.stale) {
+ const char *refname = item->util;
if (!dry_run)
result |= delete_ref(refname, NULL, 0);
abbrev_ref(refname, "refs/remotes/"));
}
- warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list);
- string_list_clear(&delete_refs_list, 0);
+ warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
+ string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states);
return result;
}
};
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
- struct argv_array cmd_args = ARGV_ARRAY_INIT;
struct string_list names = STRING_LIST_INIT_DUP;
struct string_list rollback = STRING_LIST_INIT_NODUP;
struct string_list existing_packs = STRING_LIST_INIT_DUP;
sigchain_push_common(remove_pack_on_signal);
- argv_array_push(&cmd_args, "pack-objects");
- argv_array_push(&cmd_args, "--keep-true-parents");
+ argv_array_push(&cmd.args, "pack-objects");
+ argv_array_push(&cmd.args, "--keep-true-parents");
if (!pack_kept_objects)
- argv_array_push(&cmd_args, "--honor-pack-keep");
- argv_array_push(&cmd_args, "--non-empty");
- argv_array_push(&cmd_args, "--all");
- argv_array_push(&cmd_args, "--reflog");
- argv_array_push(&cmd_args, "--indexed-objects");
+ argv_array_push(&cmd.args, "--honor-pack-keep");
+ argv_array_push(&cmd.args, "--non-empty");
+ argv_array_push(&cmd.args, "--all");
+ argv_array_push(&cmd.args, "--reflog");
+ argv_array_push(&cmd.args, "--indexed-objects");
if (window)
- argv_array_pushf(&cmd_args, "--window=%s", window);
+ argv_array_pushf(&cmd.args, "--window=%s", window);
if (window_memory)
- argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory);
+ argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory);
if (depth)
- argv_array_pushf(&cmd_args, "--depth=%s", depth);
+ argv_array_pushf(&cmd.args, "--depth=%s", depth);
if (max_pack_size)
- argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size);
+ argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size);
if (no_reuse_delta)
- argv_array_pushf(&cmd_args, "--no-reuse-delta");
+ argv_array_pushf(&cmd.args, "--no-reuse-delta");
if (no_reuse_object)
- argv_array_pushf(&cmd_args, "--no-reuse-object");
+ argv_array_pushf(&cmd.args, "--no-reuse-object");
if (write_bitmaps)
- argv_array_push(&cmd_args, "--write-bitmap-index");
+ argv_array_push(&cmd.args, "--write-bitmap-index");
if (pack_everything & ALL_INTO_ONE) {
get_non_kept_pack_filenames(&existing_packs);
if (existing_packs.nr && delete_redundant) {
if (unpack_unreachable)
- argv_array_pushf(&cmd_args,
+ argv_array_pushf(&cmd.args,
"--unpack-unreachable=%s",
unpack_unreachable);
else if (pack_everything & LOOSEN_UNREACHABLE)
- argv_array_push(&cmd_args,
+ argv_array_push(&cmd.args,
"--unpack-unreachable");
}
} else {
- argv_array_push(&cmd_args, "--unpacked");
- argv_array_push(&cmd_args, "--incremental");
+ argv_array_push(&cmd.args, "--unpacked");
+ argv_array_push(&cmd.args, "--incremental");
}
if (local)
- argv_array_push(&cmd_args, "--local");
+ argv_array_push(&cmd.args, "--local");
if (quiet)
- argv_array_push(&cmd_args, "--quiet");
+ argv_array_push(&cmd.args, "--quiet");
if (delta_base_offset)
- argv_array_push(&cmd_args, "--delta-base-offset");
+ argv_array_push(&cmd.args, "--delta-base-offset");
- argv_array_push(&cmd_args, packtmp);
+ argv_array_push(&cmd.args, packtmp);
- cmd.argv = cmd_args.argv;
cmd.git_cmd = 1;
cmd.out = -1;
cmd.no_stdin = 1;
ret = finish_command(&cmd);
if (ret)
return ret;
- argv_array_clear(&cmd_args);
if (!names.nr && !quiet)
printf("Nothing new to pack.\n");
if (delete_redundant) {
int opts = 0;
- sort_string_list(&names);
+ string_list_sort(&names);
for_each_string_list_item(item, &existing_packs) {
char *sha1;
size_t len = strlen(item->string);
*
* The value 0160000 is not normally a valid mode, and
* also just happens to be S_IFDIR + S_IFLNK
- *
- * NOTE! We *really* shouldn't depend on the S_IFxxx macros
- * always having the same values everywhere. We should use
- * our internal git values for these things, and then we can
- * translate that to the OS-specific value. It just so
- * happens that everybody shares the same bit representation
- * in the UNIX world (and apparently wider too..)
*/
#define S_IFGITLINK 0160000
#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
extern int core_preload_index;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;
+extern int protect_hfs;
+extern int protect_ntfs;
/*
* The character that begins a commented line in user-editable file
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
int daemon_avoid_alias(const char *path);
+extern int is_ntfs_dotgit(const char *name);
/* object replacement */
#define LOOKUP_REPLACE_OBJECT 1
}
return NULL;
}
+
+/*
+ * Inspect sb and determine the true "end" of the log message, in
+ * order to find where to put a new Signed-off-by: line. Ignored are
+ * trailing comment lines and blank lines, and also the traditional
+ * "Conflicts:" block that is not commented out, so that we can use
+ * "git commit -s --amend" on an existing commit that forgot to remove
+ * it.
+ *
+ * Returns the number of bytes from the tail to ignore, to be fed as
+ * the second parameter to append_signoff().
+ */
+int ignore_non_trailer(struct strbuf *sb)
+{
+ int boc = 0;
+ int bol = 0;
+ int in_old_conflicts_block = 0;
+
+ while (bol < sb->len) {
+ char *next_line;
+
+ if (!(next_line = memchr(sb->buf + bol, '\n', sb->len - bol)))
+ next_line = sb->buf + sb->len;
+ else
+ next_line++;
+
+ if (sb->buf[bol] == comment_line_char || sb->buf[bol] == '\n') {
+ /* is this the first of the run of comments? */
+ if (!boc)
+ boc = bol;
+ /* otherwise, it is just continuing */
+ } else if (starts_with(sb->buf + bol, "Conflicts:\n")) {
+ in_old_conflicts_block = 1;
+ if (!boc)
+ boc = bol;
+ } else if (in_old_conflicts_block && sb->buf[bol] == '\t') {
+ ; /* a pathname in the conflicts block */
+ } else if (boc) {
+ /* the previous was not trailing comment */
+ boc = 0;
+ in_old_conflicts_block = 0;
+ }
+ bol = next_line - sb->buf;
+ }
+ return boc ? sb->len - boc : 0;
+}
extern const char *find_commit_header(const char *msg, const char *key,
size_t *out_len);
+/* Find the end of the log message, the right place for a new trailer. */
+extern int ignore_non_trailer(struct strbuf *sb);
+
typedef void (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
void *cb_data);
return -1;
fd = _wopen(wfilename, oflags, mode);
- if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
+ if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
DWORD attrs = GetFileAttributesW(wfilename);
if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
errno = EISDIR;
--- /dev/null
+#define _POSIX_C_SOURCE 200112L
+#include <sys/stat.h> /* *stat, S_IS* */
+#include <sys/types.h> /* mode_t */
+
+static inline mode_t mode_native_to_git(mode_t native_mode)
+{
+ mode_t perm_bits = native_mode & 07777;
+ if (S_ISREG(native_mode))
+ return 0100000 | perm_bits;
+ if (S_ISDIR(native_mode))
+ return 0040000 | perm_bits;
+ if (S_ISLNK(native_mode))
+ return 0120000 | perm_bits;
+ if (S_ISBLK(native_mode))
+ return 0060000 | perm_bits;
+ if (S_ISCHR(native_mode))
+ return 0020000 | perm_bits;
+ if (S_ISFIFO(native_mode))
+ return 0010000 | perm_bits;
+ if (S_ISSOCK(native_mode))
+ return 0140000 | perm_bits;
+ /* Non-standard type bits were given. */
+ return perm_bits;
+}
+
+int git_stat(const char *path, struct stat *buf)
+{
+ int rc = stat(path, buf);
+ if (rc == 0)
+ buf->st_mode = mode_native_to_git(buf->st_mode);
+ return rc;
+}
+
+int git_fstat(int fd, struct stat *buf)
+{
+ int rc = fstat(fd, buf);
+ if (rc == 0)
+ buf->st_mode = mode_native_to_git(buf->st_mode);
+ return rc;
+}
+
+int git_lstat(const char *path, struct stat *buf)
+{
+ int rc = lstat(path, buf);
+ if (rc == 0)
+ buf->st_mode = mode_native_to_git(buf->st_mode);
+ return rc;
+}
errno = EINVAL;
return 0;
}
- uval = abs(val);
+ uval = labs(val);
uval *= factor;
- if (uval > max || abs(val) > uval) {
+ if (uval > max || labs(val) > uval) {
errno = ERANGE;
return 0;
}
return 0;
}
+ if (!strcmp(var, "core.protecthfs")) {
+ protect_hfs = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.protectntfs")) {
+ protect_ntfs = git_config_bool(var, value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
HAVE_DEV_TTY = YesPlease
COMPAT_OBJS += compat/precompose_utf8.o
BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
+ BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj
PTHREAD_LIBS =
lib =
+ BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
ifndef DEBUG
BASIC_CFLAGS += -GL -Os -MD
BASIC_LDFLAGS += -LTCG
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/dirent.o
+ BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
BASIC_LDFLAGS += -Wl,--large-address-aware
EXTLIBS += -lws2_32
GITLIBS += git.res
SNPRINTF_RETURNS_BOGUS=
fi
GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
+#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values.
+AC_CACHE_CHECK([whether the platform uses typical file type bits],
+ [ac_cv_sane_mode_bits], [
+AC_EGREP_CPP(yippeeyeswehaveit,
+ AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+[#if S_IFMT == 0170000 && \
+ S_IFREG == 0100000 && S_IFDIR == 0040000 && S_IFLNK == 0120000 && \
+ S_IFBLK == 0060000 && S_IFCHR == 0020000 && \
+ S_IFIFO == 0010000 && S_IFSOCK == 0140000
+yippeeyeswehaveit
+#endif
+]),
+ [ac_cv_sane_mode_bits=yes],
+ [ac_cv_sane_mode_bits=no])
+])
+if test $ac_cv_sane_mode_bits = yes; then
+ NEEDS_MODE_TRANSLATION=
+else
+ NEEDS_MODE_TRANSLATION=UnfortunatelyYes
+fi
+GIT_CONF_SUBST([NEEDS_MODE_TRANSLATION])
## Checks for library functions.
parse_one_symref_info(&symref, val, len);
feature_list = val + 1;
}
- sort_string_list(&symref);
+ string_list_sort(&symref);
for (; ref; ref = ref->next) {
struct string_list_item *item;
conn->in = conn->out = -1;
if (protocol == PROTO_SSH) {
- const char *ssh = getenv("GIT_SSH");
- int putty = ssh && strcasestr(ssh, "plink");
+ const char *ssh;
+ int putty;
char *ssh_host = hostandport;
const char *port = NULL;
get_host_and_port(&ssh_host, &port);
port = get_port_numeric(port);
- if (!ssh) ssh = "ssh";
+ ssh = getenv("GIT_SSH_COMMAND");
+ if (ssh) {
+ conn->use_shell = 1;
+ putty = 0;
+ } else {
+ ssh = getenv("GIT_SSH");
+ if (!ssh)
+ ssh = "ssh";
+ putty = !!strcasestr(ssh, "plink");
+ }
argv_array_push(&conn->args, ssh);
if (putty && !strcasestr(ssh, "tortoiseplink"))
__gitcomp "$__git_send_email_suppresscc_options"
return
;;
+ sendemail.transferencoding)
+ __gitcomp "7bit 8bit quoted-printable base64"
+ return
+ ;;
--get|--get-all|--unset|--unset-all)
__gitcomp_nl "$(__git_config_get_set_variables)"
return
__gitcomp_nl "$(__git_refs)"
;;
esac
+
+ case "$cur" in
+ --*)
+ __gitcomp "
+ --list --delete --verify --annotate --message --file
+ --sign --cleanup --local-user --force --column --sort
+ --contains --points-at
+ "
+ ;;
+ esac
}
_git_whatchanged ()
exit 128
}
+failed () {
+ die "unable to create new workdir '$new_workdir'!"
+}
+
if test $# -lt 2 || test $# -gt 3
then
usage "$0 <repository> <new_workdir> [<branch>]"
# don't link to a configured bare repository
isbare=$(git --git-dir="$git_dir" config --bool --get core.bare)
-if test ztrue = z$isbare
+if test ztrue = "z$isbare"
then
die "\"$git_dir\" has core.bare set to true," \
" remove from \"$git_dir/config\" to use $0"
"a complete repository."
fi
-# don't recreate a workdir over an existing repository
-if test -e "$new_workdir"
+# make sure the links in the workdir have full paths to the original repo
+git_dir=$(cd "$git_dir" && pwd) || exit 1
+
+# don't recreate a workdir over an existing directory, unless it's empty
+if test -d "$new_workdir"
then
- die "destination directory '$new_workdir' already exists."
+ if test $(ls -a1 "$new_workdir/." | wc -l) -ne 2
+ then
+ die "destination directory '$new_workdir' is not empty."
+ fi
+ cleandir="$new_workdir/.git"
+else
+ cleandir="$new_workdir"
fi
-# make sure the links use full paths
-git_dir=$(cd "$git_dir"; pwd)
+mkdir -p "$new_workdir/.git" || failed
+cleandir=$(cd "$cleandir" && pwd) || failed
-# create the workdir
-mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
+cleanup () {
+ rm -rf "$cleandir"
+}
+siglist="0 1 2 15"
+trap cleanup $siglist
# create the links to the original repo. explicitly exclude index, HEAD and
# logs/HEAD from the list since they are purely related to the current working
# directory, and should not be shared.
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
do
+ # create a containing directory if needed
case $x in
*/*)
- mkdir -p "$(dirname "$new_workdir/.git/$x")"
+ mkdir -p "$new_workdir/.git/${x%/*}"
;;
esac
- ln -s "$git_dir/$x" "$new_workdir/.git/$x"
+
+ ln -s "$git_dir/$x" "$new_workdir/.git/$x" || failed
done
-# now setup the workdir
-cd "$new_workdir"
+# commands below this are run in the context of the new workdir
+cd "$new_workdir" || failed
+
# copy the HEAD from the original repository as a default branch
-cp "$git_dir/HEAD" .git/HEAD
-# checkout the branch (either the same as HEAD from the original repository, or
-# the one that was asked for)
+cp "$git_dir/HEAD" .git/HEAD || failed
+
+# the workdir is set up. if the checkout fails, the user can fix it.
+trap - $siglist
+
+# checkout the branch (either the same as HEAD from the original repository,
+# or the one that was asked for)
git checkout -f $branch
c->path = xstrdup(value);
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
+ } else if (!strcmp(key, "quit")) {
+ c->quit = !!git_config_bool("quit", value);
}
/*
* Ignore other lines; we don't know what they mean, but
credential_do(c, c->helpers.items[i].string, "get");
if (c->username && c->password)
return;
+ if (c->quit)
+ die("credential helper '%s' told us to quit",
+ c->helpers.items[i].string);
}
credential_getpass(c);
struct string_list helpers;
unsigned approved:1,
configured:1,
+ quit:1,
use_http_path:1;
char *username;
extern void crc32_begin(struct sha1file *);
extern uint32_t crc32_end(struct sha1file *);
+static inline void sha1write_u8(struct sha1file *f, uint8_t data)
+{
+ sha1write(f, &data, sizeof(data));
+}
+
+static inline void sha1write_be32(struct sha1file *f, uint32_t data)
+{
+ data = htonl(data);
+ sha1write(f, &data, sizeof(data));
+}
+
#endif
struct startup_info *startup_info;
unsigned long pack_size_limit_cfg;
+#ifndef PROTECT_HFS_DEFAULT
+#define PROTECT_HFS_DEFAULT 0
+#endif
+int protect_hfs = PROTECT_HFS_DEFAULT;
+
+#ifndef PROTECT_NTFS_DEFAULT
+#define PROTECT_NTFS_DEFAULT 0
+#endif
+int protect_ntfs = PROTECT_NTFS_DEFAULT;
+
/*
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
static const char *argv_exec_path;
static const char *argv0_path;
-const char *system_path(const char *path)
+char *system_path(const char *path)
{
#ifdef RUNTIME_PREFIX
static const char *prefix;
struct strbuf d = STRBUF_INIT;
if (is_absolute_path(path))
- return path;
+ return xstrdup(path);
#ifdef RUNTIME_PREFIX
assert(argv0_path);
#endif
strbuf_addf(&d, "%s/%s", prefix, path);
- path = strbuf_detach(&d, NULL);
- return path;
+ return strbuf_detach(&d, NULL);
}
const char *git_extract_argv0_path(const char *argv0)
extern int execv_git_cmd(const char **argv); /* NULL terminated */
LAST_ARG_MUST_BE_NULL
extern int execl_git_cmd(const char *cmd, ...);
-extern const char *system_path(const char *path);
+extern char *system_path(const char *path);
#endif /* GIT_EXEC_CMD_H */
#include "tag.h"
#include "fsck.h"
#include "refs.h"
+#include "utf8.h"
static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
{
has_empty_name |= !*name;
has_dot |= !strcmp(name, ".");
has_dotdot |= !strcmp(name, "..");
- has_dotgit |= !strcmp(name, ".git");
+ has_dotgit |= (!strcmp(name, ".git") ||
+ is_hfs_dotgit(name) ||
+ is_ntfs_dotgit(name));
has_zero_pad |= *(char *)desc.buffer == '0';
update_tree_entry(&desc);
u,utf8 recode into utf8 (default)
k,keep pass -k flag to git-mailinfo
keep-non-patch pass -b flag to git-mailinfo
+m,message-id pass -m flag to git-mailinfo
keep-cr pass --keep-cr flag to git-mailsplit for mbox format
no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
c,scissors strip everything before a scissors line
prec=4
dotest="$GIT_DIR/rebase-apply"
sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort=
-resolvemsg= resume= scissors= no_inbody_headers=
+messageid= resolvemsg= resume= scissors= no_inbody_headers=
git_apply_opt=
committer_date_is_author_date=
ignore_date=
allow_rerere_autoupdate=
gpg_sign_opt=
+if test "$(git config --bool --get am.messageid)" = true
+then
+ messageid=t
+fi
+
if test "$(git config --bool --get am.keepcr)" = true
then
keepcr=t
utf8=t ;; # this is now default
--no-utf8)
utf8= ;;
+ -m|--message-id)
+ messageid=t ;;
+ --no-message-id)
+ messageid=f ;;
-k|--keep)
keep=t ;;
--keep-non-patch)
echo "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep"
+ echo "$messageid" >"$dotest/messageid"
echo "$scissors" >"$dotest/scissors"
echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
echo "$GIT_QUIET" >"$dotest/quiet"
*)
keep= ;;
esac
+case "$(cat "$dotest/messageid")" in
+t)
+ messageid=-m ;;
+f)
+ messageid= ;;
+esac
case "$(cat "$dotest/scissors")" in
t)
scissors=--scissors ;;
get_author_ident_from_commit "$commit" >"$dotest/author-script"
git diff-tree --root --binary --full-index "$commit" >"$dotest/patch"
else
- git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
+ git mailinfo $keep $no_inbody_headers $messageid $scissors $utf8 "$dotest/msg" "$dotest/patch" \
<"$dotest/$msgnum" >"$dotest/info" ||
stop_here $this
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
!defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
- !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__)
+ !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__) && \
+ !defined(__CYGWIN__)
#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
#define on_disk_bytes(st) ((st).st_blocks * 512)
#endif
+#ifdef NEEDS_MODE_TRANSLATION
+#undef S_IFMT
+#undef S_IFREG
+#undef S_IFDIR
+#undef S_IFLNK
+#undef S_IFBLK
+#undef S_IFCHR
+#undef S_IFIFO
+#undef S_IFSOCK
+#define S_IFMT 0170000
+#define S_IFREG 0100000
+#define S_IFDIR 0040000
+#define S_IFLNK 0120000
+#define S_IFBLK 0060000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_IFSOCK 0140000
+#ifdef stat
+#undef stat
+#endif
+#define stat(path, buf) git_stat(path, buf)
+extern int git_stat(const char *, struct stat *);
+#ifdef fstat
+#undef fstat
+#endif
+#define fstat(fd, buf) git_fstat(fd, buf)
+extern int git_fstat(int, struct stat *);
+#ifdef lstat
+#undef lstat
+#endif
+#define lstat(path, buf) git_lstat(path, buf)
+extern int git_lstat(const char *, struct stat *);
+#endif
+
#define DEFAULT_PACKED_GIT_LIMIT \
((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
shift 7
done
fi
+
+exit 0
check_unchanged () {
if test "$MERGED" -nt "$BACKUP"
then
- status=0
+ return 0
else
while true
do
printf "Was the merge successful? [y/n] "
read answer || return 1
case "$answer" in
- y*|Y*) status=0; break ;;
- n*|N*) status=1; break ;;
+ y*|Y*) return 0 ;;
+ n*|N*) return 1 ;;
esac
done
fi
diff_cmd () {
( eval $merge_tool_cmd )
- status=$?
- return $status
}
merge_cmd () {
then
touch "$BACKUP"
( eval $merge_tool_cmd )
- status=$?
check_unchanged
else
( eval $merge_tool_cmd )
- status=$?
fi
- return $status
}
}
}
diff_cmd () {
- status=1
- return $status
+ return 1
}
merge_cmd () {
- status=1
- return $status
+ return 1
}
translate_merge_tool_path () {
merge_tool_path=$(get_merge_tool_path "$1") || exit
base_present="$2"
- status=0
# Bring tool-specific functions into scope
setup_tool "$1" || return 1
else
run_diff_cmd "$1"
fi
- status=$?
- return $status
}
# Run a either a configured or built-in diff tool
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
-last_status=0
-rollup_status=0
files=
if test $# -eq 0
IFS='
'
+rc=0
for i in $files
do
- if test $last_status -ne 0
- then
- prompt_after_failed_merge || exit 1
- fi
printf "\n"
- merge_file "$i"
- last_status=$?
- if test $last_status -ne 0
+ if ! merge_file "$i"
then
- rollup_status=1
+ rc=1
+ prompt_after_failed_merge || exit 1
fi
done
-exit $rollup_status
+exit $rc
--compose * Open an editor for introduction.
--compose-encoding <str> * Encoding to assume for introduction.
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
+ --transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
Sending:
--envelope-sender <str> * Email envelope sender.
my (@suppress_cc);
my ($auto_8bit_encoding);
my ($compose_encoding);
+my ($target_xfer_encoding);
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
"from" => \$sender,
"assume8bitencoding" => \$auto_8bit_encoding,
"composeencoding" => \$compose_encoding,
+ "transferencoding" => \$target_xfer_encoding,
);
my %config_path_settings = (
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
"validate!" => \$validate,
+ "transfer-encoding=s" => \$target_xfer_encoding,
"format-patch!" => \$format_patch,
"8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding,
my $author_encoding;
my $has_content_type;
my $body_encoding;
+ my $xfer_encoding;
+ my $has_mime_version;
@to = ();
@cc = ();
@xh = ();
}
push @xh, $_;
}
+ elsif (/^MIME-Version/i) {
+ $has_mime_version = 1;
+ push @xh, $_;
+ }
elsif (/^Message-Id: (.*)/i) {
$message_id = $1;
}
+ elsif (/^Content-Transfer-Encoding: (.*)/i) {
+ $xfer_encoding = $1 if not defined $xfer_encoding;
+ }
elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_;
}
if defined $cc_cmd && !$suppress_cc{'cccmd'};
if ($broken_encoding{$t} && !$has_content_type) {
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
$has_content_type = 1;
- push @xh, "MIME-Version: 1.0",
- "Content-Type: text/plain; charset=$auto_8bit_encoding",
- "Content-Transfer-Encoding: 8bit";
+ push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
$body_encoding = $auto_8bit_encoding;
}
}
}
else {
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
$has_content_type = 1;
push @xh,
- 'MIME-Version: 1.0',
- "Content-Type: text/plain; charset=$author_encoding",
- 'Content-Transfer-Encoding: 8bit';
+ "Content-Type: text/plain; charset=$author_encoding";
}
}
}
+ if (defined $target_xfer_encoding) {
+ $xfer_encoding = '8bit' if not defined $xfer_encoding;
+ $message = apply_transfer_encoding(
+ $message, $xfer_encoding, $target_xfer_encoding);
+ $xfer_encoding = $target_xfer_encoding;
+ }
+ if (defined $xfer_encoding) {
+ push @xh, "Content-Transfer-Encoding: $xfer_encoding";
+ }
+ if (defined $xfer_encoding or $has_content_type) {
+ unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
+ }
$needs_confirm = (
$confirm eq "always" or
$smtp->quit if $smtp;
+sub apply_transfer_encoding {
+ my $message = shift;
+ my $from = shift;
+ my $to = shift;
+
+ return $message if ($from eq $to and $from ne '7bit');
+
+ require MIME::QuotedPrint;
+ require MIME::Base64;
+
+ $message = MIME::QuotedPrint::decode($message)
+ if ($from eq 'quoted-printable');
+ $message = MIME::Base64::decode($message)
+ if ($from eq 'base64');
+
+ die "cannot send message as 7bit"
+ if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
+ return $message
+ if ($to eq '7bit' or $to eq '8bit');
+ return MIME::QuotedPrint::encode($message, "\n", 0)
+ if ($to eq 'quoted-printable');
+ return MIME::Base64::encode($message, "\n")
+ if ($to eq 'base64');
+ die "invalid transfer encoding";
+}
+
sub unique_email_list {
my %seen;
my @emails;
echo exit $?
)"
else
- dashless=$(basename "$0" | sed -e 's/-/ /')
+ dashless=$(basename -- "$0" | sed -e 's/-/ /')
usage() {
die "usage: $dashless $USAGE"
}
{ "write-tree", cmd_write_tree, RUN_SETUP },
};
-int is_builtin(const char *s)
+static struct cmd_struct *get_builtin(const char *s)
{
int i;
for (i = 0; i < ARRAY_SIZE(commands); i++) {
- struct cmd_struct *p = commands+i;
+ struct cmd_struct *p = commands + i;
if (!strcmp(s, p->cmd))
- return 1;
+ return p;
}
- return 0;
+ return NULL;
+}
+
+int is_builtin(const char *s)
+{
+ return !!get_builtin(s);
}
static void handle_builtin(int argc, const char **argv)
const char *cmd = argv[0];
int i;
static const char ext[] = STRIP_EXTENSION;
+ struct cmd_struct *builtin;
if (sizeof(ext) > 1) {
i = strlen(argv[0]) - strlen(ext);
argv[0] = cmd = "help";
}
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- struct cmd_struct *p = commands+i;
- if (strcmp(p->cmd, cmd))
- continue;
- if (saved_environment && (p->option & NO_SETUP)) {
+ builtin = get_builtin(cmd);
+ if (builtin) {
+ if (saved_environment && (builtin->option & NO_SETUP))
restore_env();
- break;
- }
- exit(run_builtin(p, argc, argv));
+ else
+ exit(run_builtin(builtin, argc, argv));
}
}
use Time::HiRes qw(gettimeofday tv_interval);
binmode STDOUT, ':utf8';
+if (!defined($CGI::VERSION) || $CGI::VERSION < 4.08) {
+ eval 'sub CGI::multi_param { CGI::param(@_) }'
+}
+
our $t0 = [ gettimeofday() ];
our $number_of_git_cmds = 0;
while (my ($name, $symbol) = each %cgi_param_mapping) {
if ($symbol eq 'opt') {
- $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ];
+ $input_params{$name} = [ map { decode_utf8($_) } $cgi->multi_param($symbol) ];
} else {
$input_params{$name} = decode_utf8($cgi->param($symbol));
}
char *old_name, char *old_email)
{
struct mailmap_entry *me;
- int index;
+ struct string_list_item *item;
if (old_email == NULL) {
old_email = new_email;
new_email = NULL;
}
- if ((index = string_list_find_insert_index(map, old_email, 1)) < 0) {
- /* mailmap entry exists, invert index value */
- index = -1 - index;
- me = (struct mailmap_entry *)map->items[index].util;
+ item = string_list_insert(map, old_email);
+ if (item->util) {
+ me = (struct mailmap_entry *)item->util;
} else {
- /* create mailmap entry */
- struct string_list_item *item;
-
- item = string_list_insert_at_index(map, index, old_email);
me = xcalloc(1, sizeof(struct mailmap_entry));
me->namemap.strdup_strings = 1;
me->namemap.cmp = namemap_cmp;
}
if (old_name == NULL) {
- debug_mm("mailmap: adding (simple) entry for %s at index %d\n",
- old_email, index);
+ debug_mm("mailmap: adding (simple) entry for '%s'\n", old_email);
+
/* Replace current name and new email for simple entry */
if (new_name) {
free(me->name);
}
} else {
struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
- debug_mm("mailmap: adding (complex) entry for %s at index %d\n",
- old_email, index);
+ debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
if (new_name)
mi->name = xstrdup(new_name);
if (new_email)
}
static int save_files_dirs(const unsigned char *sha1,
- const char *base, int baselen, const char *path,
+ struct strbuf *base, const char *path,
unsigned int mode, int stage, void *context)
{
- int len = strlen(path);
- char *newpath = xmalloc(baselen + len + 1);
+ int baselen = base->len;
struct merge_options *o = context;
- memcpy(newpath, base, baselen);
- memcpy(newpath + baselen, path, len);
- newpath[baselen + len] = '\0';
+ strbuf_addstr(base, path);
if (S_ISDIR(mode))
- string_list_insert(&o->current_directory_set, newpath);
+ string_list_insert(&o->current_directory_set, base->buf);
else
- string_list_insert(&o->current_file_set, newpath);
- free(newpath);
+ string_list_insert(&o->current_file_set, base->buf);
+ strbuf_setlen(base, baselen);
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
}
"$merge_tool_path" --merge \
--result="$MERGED" "$LOCAL" "$REMOTE"
fi
- status=$?
}
"$LOCAL" "$REMOTE" \
"$(basename "$MERGED")"
fi
- status=$?
}
translate_merge_tool_path() {
-o "$MERGED" "$LOCAL" "$REMOTE" \
>/dev/null 2>&1
fi
- status=$?
}
if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
goto out;
string_list_remove_empty_items(&sort_uniq_list, 0);
- sort_string_list(&sort_uniq_list);
+ string_list_sort(&sort_uniq_list);
string_list_remove_duplicates(&sort_uniq_list, 0);
/* create a new blob object from sort_uniq_list */
if (!sha1)
return;
- if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen ||
- type != OBJ_BLOB) {
+ if (!(msg = read_sha1_file(sha1, &type, &msglen)) || type != OBJ_BLOB) {
free(msg);
return;
}
for (i = 0; i < writer.selected_nr; ++i) {
struct bitmapped_commit *stored = &writer.selected[i];
- struct bitmap_disk_entry on_disk;
int commit_pos =
sha1_pos(stored->commit->object.sha1, index, index_nr, sha1_access);
if (commit_pos < 0)
die("BUG: trying to write commit not in index");
- on_disk.object_pos = htonl(commit_pos);
- on_disk.xor_offset = stored->xor_offset;
- on_disk.flags = stored->flags;
+ sha1write_be32(f, commit_pos);
+ sha1write_u8(f, stored->xor_offset);
+ sha1write_u8(f, stored->flags);
- sha1write(f, &on_disk, sizeof(on_disk));
dump_bitmap(f, stored->write_as);
}
}
return stored;
}
+static inline uint32_t read_be32(const unsigned char *buffer, size_t *pos)
+{
+ uint32_t result = get_be32(buffer + *pos);
+ (*pos) += sizeof(result);
+ return result;
+}
+
+static inline uint8_t read_u8(const unsigned char *buffer, size_t *pos)
+{
+ return buffer[(*pos)++];
+}
+
static int load_bitmap_entries_v1(struct bitmap_index *index)
{
static const size_t MAX_XOR_OFFSET = 160;
uint32_t i;
struct stored_bitmap **recent_bitmaps;
- struct bitmap_disk_entry *entry;
recent_bitmaps = xcalloc(MAX_XOR_OFFSET, sizeof(struct stored_bitmap));
uint32_t commit_idx_pos;
const unsigned char *sha1;
- entry = (struct bitmap_disk_entry *)(index->map + index->map_pos);
- index->map_pos += sizeof(struct bitmap_disk_entry);
+ commit_idx_pos = read_be32(index->map, &index->map_pos);
+ xor_offset = read_u8(index->map, &index->map_pos);
+ flags = read_u8(index->map, &index->map_pos);
- commit_idx_pos = ntohl(entry->object_pos);
sha1 = nth_packed_object_sha1(index->pack, commit_idx_pos);
- xor_offset = (int)entry->xor_offset;
- flags = (int)entry->flags;
-
bitmap = read_bitmap_1(index);
if (!bitmap)
return -1;
#include "khash.h"
#include "pack-objects.h"
-struct bitmap_disk_entry {
- uint32_t object_pos;
- uint8_t xor_offset;
- uint8_t flags;
-} __attribute__((packed));
-
struct bitmap_disk_header {
char magic[4];
uint16_t version;
}
}
}
+
+static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
+{
+ if (len < skip)
+ return 0;
+ len -= skip;
+ path += skip;
+ while (len-- > 0) {
+ char c = *(path++);
+ if (c != ' ' && c != '.')
+ return 0;
+ }
+ return 1;
+}
+
+int is_ntfs_dotgit(const char *name)
+{
+ int len;
+
+ for (len = 0; ; len++)
+ if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
+ if (only_spaces_and_periods(name, len, 4) &&
+ !strncasecmp(name, ".git", 4))
+ return 1;
+ if (only_spaces_and_periods(name, len, 5) &&
+ !strncasecmp(name, "git~1", 5))
+ return 1;
+ if (name[len] != '\\')
+ return 0;
+ name += len + 1;
+ len = -1;
+ }
+}
r = do_askpass(askpass, prompt);
}
- if (!r)
- r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
if (!r) {
- /* prompts already contain ": " at the end */
- die("could not read %s%s", prompt, strerror(errno));
+ const char *err;
+
+ if (git_env_bool("GIT_TERMINAL_PROMPT", 1)) {
+ r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
+ err = strerror(errno);
+ } else {
+ err = "terminal prompts disabled";
+ }
+ if (!r) {
+ /* prompts already contain ": " at the end */
+ die("could not read %s%s", prompt, err);
+ }
}
return r;
}
fputc(terminator, fp);
}
-void write_name_quotedpfx(const char *pfx, size_t pfxlen,
- const char *name, FILE *fp, int terminator)
-{
- int needquote = 0;
-
- if (terminator) {
- needquote = next_quote_pos(pfx, pfxlen) < pfxlen
- || name[next_quote_pos(name, -1)];
- }
- if (needquote) {
- fputc('"', fp);
- quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
- quote_c_style(name, NULL, fp, 1);
- fputc('"', fp);
- } else {
- fwrite(pfx, pfxlen, 1, fp);
- fputs(name, fp);
- }
- fputc(terminator, fp);
-}
-
void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator)
{
extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
- const char *name, FILE *, int terminator);
extern void write_name_quoted_relative(const char *name, const char *prefix,
FILE *fp, int terminator);
#include "varint.h"
#include "split-index.h"
#include "sigchain.h"
+#include "utf8.h"
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
unsigned int options);
* shares the path end test with the ".." case.
*/
case 'g':
- if (rest[1] != 'i')
+ case 'G':
+ if (rest[1] != 'i' && rest[1] != 'I')
break;
- if (rest[2] != 't')
+ if (rest[2] != 't' && rest[2] != 'T')
break;
rest += 2;
/* fallthrough */
return 1;
if (is_dir_sep(c)) {
inside:
+ if (protect_hfs && is_hfs_dotgit(path))
+ return 0;
+ if (protect_ntfs && is_ntfs_dotgit(path))
+ return 0;
c = *path++;
if ((c == '.' && !verify_dotfile(path)) ||
is_dir_sep(c) || c == '\0')
lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags);
if (lock->lock_fd < 0) {
+ last_errno = errno;
if (errno == ENOENT && --attempts_remaining > 0)
/*
* Maybe somebody just deleted one of the
* again:
*/
goto retry;
- else
- unable_to_lock_die(ref_file, errno);
+ else {
+ struct strbuf err = STRBUF_INIT;
+ unable_to_lock_message(ref_file, errno, &err);
+ error("%s", err.buf);
+ strbuf_reset(&err);
+ goto error_return;
+ }
}
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
return 0;
}
-int repack_without_refs(const char **refnames, int n, struct strbuf *err)
+int repack_without_refs(struct string_list *refnames, struct strbuf *err)
{
struct ref_dir *packed;
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
- struct string_list_item *ref_to_delete;
- int i, ret, removed = 0;
+ struct string_list_item *refname, *ref_to_delete;
+ int ret, needs_repacking = 0, removed = 0;
assert(err);
/* Look for a packed ref */
- for (i = 0; i < n; i++)
- if (get_packed_ref(refnames[i]))
+ for_each_string_list_item(refname, refnames) {
+ if (get_packed_ref(refname->string)) {
+ needs_repacking = 1;
break;
+ }
+ }
/* Avoid locking if we have nothing to do */
- if (i == n)
+ if (!needs_repacking)
return 0; /* no refname exists in packed refs */
if (lock_packed_refs(0)) {
packed = get_packed_refs(&ref_cache);
/* Remove refnames from the cache */
- for (i = 0; i < n; i++)
- if (remove_entry(packed, refnames[i]) != -1)
+ for_each_string_list_item(refname, refnames)
+ if (remove_entry(packed, refname->string) != -1)
removed = 1;
if (!removed) {
/*
bp = find_beginning_of_line(buf, scanp);
- if (*bp != '\n') {
- strbuf_splice(&sb, 0, 0, buf, endp - buf);
- if (pos)
- break; /* need to fill another block */
- scanp = buf - 1; /* leave loop */
- } else {
+ if (*bp == '\n') {
/*
- * (bp + 1) thru endp is the beginning of the
- * current line we have in sb
+ * The newline is the end of the previous line,
+ * so we know we have complete line starting
+ * at (bp + 1). Prefix it onto any prior data
+ * we collected for the line and process it.
*/
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ if (ret)
+ break;
+ } else if (!pos) {
+ /*
+ * We are at the start of the buffer, and the
+ * start of the file; there is no previous
+ * line, and we have everything for this one.
+ * Process it, and we can end the loop.
+ */
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ break;
}
- ret = show_one_reflog_ent(&sb, fn, cb_data);
- strbuf_reset(&sb);
- if (ret)
+
+ if (bp == buf) {
+ /*
+ * We are at the start of the buffer, and there
+ * is more file to read backwards. Which means
+ * we are in the middle of a line. Note that we
+ * may get here even if *bp was a newline; that
+ * just means we are at the exact end of the
+ * previous line, rather than some spot in the
+ * middle.
+ *
+ * Save away what we have to be combined with
+ * the data from the next read.
+ */
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
break;
+ }
}
}
if (!ret && sb.len)
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ die("BUG: reverse reflog parser had leftover data");
fclose(logfp);
strbuf_release(&sb);
int ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
{
- int ret = 0, delnum = 0, i;
- const char **delnames;
+ int ret = 0, i;
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
+ struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
+ struct string_list_item *ref_to_delete;
assert(err);
return 0;
}
- /* Allocate work space */
- delnames = xmalloc(sizeof(*delnames) * n);
-
/* Copy, sort, and reject duplicate refs */
qsort(updates, n, sizeof(*updates), ref_update_compare);
if (ref_update_reject_duplicates(updates, n, err)) {
}
if (!(update->flags & REF_ISPRUNING))
- delnames[delnum++] = update->lock->ref_name;
+ string_list_append(&refs_to_delete,
+ update->lock->ref_name);
}
}
- if (repack_without_refs(delnames, delnum, err)) {
+ if (repack_without_refs(&refs_to_delete, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
- for (i = 0; i < delnum; i++)
- unlink_or_warn(git_path("logs/%s", delnames[i]));
+ for_each_string_list_item(ref_to_delete, &refs_to_delete)
+ unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
clear_loose_ref_cache(&ref_cache);
cleanup:
for (i = 0; i < n; i++)
if (updates[i]->lock)
unlock_ref(updates[i]->lock);
- free(delnames);
+ string_list_clear(&refs_to_delete, 0);
return ret;
}
*/
int pack_refs(unsigned int flags);
-extern int repack_without_refs(const char **refnames, int n,
+/*
+ * Rewrite the packed-refs file, omitting any refs listed in
+ * 'refnames'. On error, packed-refs will be unchanged, the return
+ * value is nonzero, and a message about the error is written to the
+ * 'err' strbuf.
+ *
+ * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
+ */
+extern int repack_without_refs(struct string_list *refnames,
struct strbuf *err);
extern int ref_exists(const char *);
}
clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
- sort_string_list(&dst_tag);
+ string_list_sort(&dst_tag);
/* Collect tags they do not have. */
for (ref = src; ref; ref = ref->next) {
for ( ; ref; ref = ref->next)
string_list_append_nodup(ref_index, ref->name)->util = ref;
- sort_string_list(ref_index);
+ string_list_sort(ref_index);
}
/*
info.ref_count = ref_count;
for (ref = fetch_map; ref; ref = ref->next)
string_list_append(&ref_names, ref->name);
- sort_string_list(&ref_names);
+ string_list_sort(&ref_names);
for_each_ref(get_stale_heads_cb, &info);
string_list_clear(&ref_names, 0);
return stale_refs;
return ret;
}
-
-int run_hook_with_custom_index(const char *index_file, const char *name, ...)
-{
- const char *hook_env[3] = { NULL };
- char index[PATH_MAX];
- va_list args;
- int ret;
-
- snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
- hook_env[0] = index;
-
- va_start(args, name);
- ret = run_hook_ve(hook_env, name, args);
- va_end(args);
-
- return ret;
-}
extern int run_hook_le(const char *const *env, const char *name, ...);
extern int run_hook_ve(const char *const *env, const char *name, va_list args);
-LAST_ARG_MUST_BE_NULL
-__attribute__((deprecated))
-extern int run_hook_with_custom_index(const char *index_file, const char *name, ...);
-
#define RUN_COMMAND_NO_STDIN 1
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
#define RUN_COMMAND_STDOUT_TO_STDERR 4
return 0;
}
+void append_conflicts_hint(struct strbuf *msgbuf)
+{
+ int i;
+
+ strbuf_addch(msgbuf, '\n');
+ strbuf_commented_addf(msgbuf, "Conflicts:\n");
+ for (i = 0; i < active_nr;) {
+ const struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
+}
+
static int do_recursive_merge(struct commit *base, struct commit *next,
const char *base_label, const char *next_label,
unsigned char *head, struct strbuf *msgbuf,
if (opts->signoff)
append_signoff(msgbuf, 0, 0);
- if (!clean) {
- int i;
- strbuf_addstr(msgbuf, "\nConflicts:\n");
- for (i = 0; i < active_nr;) {
- const struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- strbuf_addch(msgbuf, '\t');
- strbuf_addstr(msgbuf, ce->name);
- strbuf_addch(msgbuf, '\n');
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
- }
- }
+ if (!clean)
+ append_conflicts_hint(msgbuf);
return !clean;
}
extern const char sign_off_header[];
void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
+void append_conflicts_hint(struct strbuf *msgbuf);
#endif
if (!report_garbage)
return;
- sort_string_list(list);
+ string_list_sort(list);
for (i = 0; i < list->nr; i++) {
const char *path = list->items[i].string;
int status, exists;
static char hex[41];
- exists = has_sha1_file(sha1);
memcpy(hex, sha1_to_hex(sha1), 40);
if (len == 40 || !len)
return hex;
+ exists = has_sha1_file(sha1);
while (len < 40) {
unsigned char sha1_ret[20];
status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
struct string_list_item *string_list_insert(struct string_list *list, const char *string)
{
- return string_list_insert_at_index(list, -1, string);
-}
-
-struct string_list_item *string_list_insert_at_index(struct string_list *list,
- int insert_at, const char *string)
-{
- int index = add_entry(insert_at, list, string);
+ int index = add_entry(-1, list, string);
if (index < 0)
index = -1 - index;
/* Yuck */
static compare_strings_fn compare_for_qsort;
-/* Only call this from inside sort_string_list! */
+/* Only call this from inside string_list_sort! */
static int cmp_items(const void *a, const void *b)
{
const struct string_list_item *one = a;
return compare_for_qsort(one->string, two->string);
}
-void sort_string_list(struct string_list *list)
+void string_list_sort(struct string_list *list)
{
compare_for_qsort = list->cmp ? list->cmp : strcmp;
qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
int string_list_has_string(const struct string_list *list, const char *string);
int string_list_find_insert_index(const struct string_list *list, const char *string,
int negative_existing_index);
+/*
+ * Inserts the given string into the sorted list.
+ * If the string already exists, the list is not altered.
+ * Returns the string_list_item, the string is part of.
+ */
struct string_list_item *string_list_insert(struct string_list *list, const char *string);
-struct string_list_item *string_list_insert_at_index(struct string_list *list,
- int insert_at, const char *string);
+
+/*
+ * Checks if the given string is part of a sorted list. If it is part of the list,
+ * return the coresponding string_list_item, NULL otherwise.
+ */
struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
/*
*/
struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);
-void sort_string_list(struct string_list *list);
+void string_list_sort(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);
dies in an unexpected way (e.g. segfault).
On the other hand, don't use test_must_fail for running regular
- platform commands; just use '! cmd'.
+ platform commands; just use '! cmd'. We are not in the business
+ of verifying that the world given to us sanely works.
- use perl without spelling it as "$PERL_PATH". This is to help our
friends on Windows where the platform Perl often adds CR before
echo "expected a directory $1, a file $1/config and $1/refs"
return 1
fi
+
+ if test_have_prereq POSIXPERM && test -x "$1/config"
+ then
+ echo "$1/config is executable?"
+ return 1
+ fi
+
bare=$(cd "$1" && git config --bool core.bare)
worktree=$(cd "$1" && git config core.worktree) ||
worktree=unset
git checkout -f master
'
-$test_case 'rename (case change)' '
+test_expect_success 'rename (case change)' '
git mv camelcase CamelCase &&
git commit -m "rename"
'
test_cache_tree
'
-test_expect_success 'commit --interactive gives cache-tree on partial commit' '
+test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '
cat <<-\EOT >foo.c &&
int foo()
{
EOF
'
+test_expect_success 'helpers can abort the process' '
+ test_must_fail git \
+ -c credential.helper="!f() { echo quit=1; }; f" \
+ -c credential.helper="verbatim foo bar" \
+ credential fill >stdout &&
+ >expect &&
+ test_cmp expect stdout
+'
+
test_done
--- /dev/null
+#!/bin/sh
+
+test_description='check that read-tree rejects confusing paths'
+. ./test-lib.sh
+
+test_expect_success 'create base tree' '
+ echo content >file &&
+ git add file &&
+ git commit -m base &&
+ blob=$(git rev-parse HEAD:file) &&
+ tree=$(git rev-parse HEAD^{tree})
+'
+
+test_expect_success 'enable core.protectHFS for rejection tests' '
+ git config core.protectHFS true
+'
+
+test_expect_success 'enable core.protectNTFS for rejection tests' '
+ git config core.protectNTFS true
+'
+
+while read path pretty; do
+ : ${pretty:=$path}
+ case "$path" in
+ *SPACE)
+ path="${path%SPACE} "
+ ;;
+ esac
+ test_expect_success "reject $pretty at end of path" '
+ printf "100644 blob %s\t%s" "$blob" "$path" >tree &&
+ bogus=$(git mktree <tree) &&
+ test_must_fail git read-tree $bogus
+ '
+
+ test_expect_success "reject $pretty as subtree" '
+ printf "040000 tree %s\t%s" "$tree" "$path" >tree &&
+ bogus=$(git mktree <tree) &&
+ test_must_fail git read-tree $bogus
+ '
+done <<-EOF
+.
+..
+.git
+.GIT
+${u200c}.Git {u200c}.Git
+.gI${u200c}T .gI{u200c}T
+.GiT${u200c} .GiT{u200c}
+git~1
+.git.SPACE .git.{space}
+.\\\\.GIT\\\\foobar backslashes
+.git\\\\foobar backslashes2
+EOF
+
+test_expect_success 'utf-8 paths allowed with core.protectHFS off' '
+ test_when_finished "git read-tree HEAD" &&
+ test_config core.protectHFS false &&
+ printf "100644 blob %s\t%s" "$blob" ".gi${u200c}t" >tree &&
+ ok=$(git mktree <tree) &&
+ git read-tree $ok
+'
+
+test_done
test_cmp expect actual
'
+# Triggering the bug detected by this test requires a newline to fall
+# exactly BUFSIZ-1 bytes from the end of the file. We don't know
+# what that value is, since it's platform dependent. However, if
+# we choose some value N, we also catch any D which divides N evenly
+# (since we will read backwards in chunks of D). So we choose 8K,
+# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
+#
+# Each line is 114 characters, so we need 75 to still have a few before the
+# last 8K. The 89-character padding on the final entry lines up our
+# newline exactly.
+test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
+ git checkout -b reflogskip &&
+ z38=00000000000000000000000000000000000000 &&
+ ident="abc <xyz> 0000000001 +0000" &&
+ for i in $(test_seq 1 75); do
+ printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" &&
+ if test $i = 75; then
+ for j in $(test_seq 1 89); do
+ printf X
+ done
+ else
+ printf X
+ fi &&
+ printf "\n"
+ done >.git/logs/refs/heads/reflogskip &&
+ git rev-parse reflogskip@{73} >actual &&
+ echo ${z38}03 >expect &&
+ test_cmp expect actual
+'
+
test_done
)
'
-test_expect_success 'fsck notices "." and ".." in trees' '
- (
- git init dots &&
- cd dots &&
- blob=$(echo foo | git hash-object -w --stdin) &&
- tab=$(printf "\\t") &&
- git mktree <<-EOF &&
- 100644 blob $blob$tab.
- 100644 blob $blob$tab..
- EOF
- git fsck 2>out &&
- cat out &&
- grep "warning.*\\." out
- )
-'
-
-test_expect_success 'fsck notices ".git" in trees' '
- (
- git init dotgit &&
- cd dotgit &&
- blob=$(echo foo | git hash-object -w --stdin) &&
- tab=$(printf "\\t") &&
- git mktree <<-EOF &&
- 100644 blob $blob$tab.git
- EOF
- git fsck 2>out &&
- cat out &&
- grep "warning.*\\.git" out
- )
-'
+while read name path pretty; do
+ while read mode type; do
+ : ${pretty:=$path}
+ test_expect_success "fsck notices $pretty as $type" '
+ (
+ git init $name-$type &&
+ cd $name-$type &&
+ echo content >file &&
+ git add file &&
+ git commit -m base &&
+ blob=$(git rev-parse :file) &&
+ tree=$(git rev-parse HEAD^{tree}) &&
+ value=$(eval "echo \$$type") &&
+ printf "$mode $type %s\t%s" "$value" "$path" >bad &&
+ bad_tree=$(git mktree <bad) &&
+ git fsck 2>out &&
+ cat out &&
+ grep "warning.*tree $bad_tree" out
+ )'
+ done <<-\EOF
+ 100644 blob
+ 040000 tree
+ EOF
+done <<-EOF
+dot .
+dotdot ..
+dotgit .git
+dotgit-case .GIT
+dotgit-unicode .gI${u200c}T .gI{u200c}T
+dotgit-case2 .Git
+git-tilde1 git~1
+dotgitdot .git.
+dot-backslash-case .\\\\.GIT\\\\foobar
+dotgit-case-backslash .git\\\\foobar
+EOF
# create a static test repo which is broken by omitting
# one particular object ($1, which is looked up via rev-parse
test_cmp expect.next0 actual.next0
'
+test_expect_success 'do not touch files that are already up-to-date' '
+ git reset --hard &&
+ echo one >file1 &&
+ echo two >file2 &&
+ git add file1 file2 &&
+ git commit -m base &&
+ echo modified >file1 &&
+ test-chmtime =1000000000 file2 &&
+ git update-index -q --refresh &&
+ git checkout HEAD -- file1 file2 &&
+ echo one >expect &&
+ test_cmp expect file1 &&
+ echo "1000000000 file2" >expect &&
+ test-chmtime -v +0 file2 >actual &&
+ test_cmp expect actual
+'
+
test_done
'
test_expect_success 'ls-tree a[a] matches literally' '
- cat >expected <<EOF &&
-100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three
-EOF
+ cat >expect <<-\EOF &&
+ 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three
+ EOF
git ls-tree -r HEAD "a[a]" >actual &&
- test_cmp expected actual
+ test_cmp expect actual
+'
+
+test_expect_success 'ls-tree outside prefix' '
+ cat >expect <<-\EOF &&
+ 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 ../a[a]/three
+ EOF
+ ( cd aa && git ls-tree -r HEAD "../a[a]"; ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_failure 'ls-tree does not yet support negated pathspec' '
+ git ls-files ":(exclude)a" "a*" >expect &&
+ git ls-tree --name-only -r HEAD ":(exclude)a" "a*" >actual &&
+ test_cmp expect actual
'
test_done
. ./test-lib.sh
-cat > fake_editor.sh << \EOF
-#!/bin/sh
-echo "$MSG" > "$1"
-echo "$MSG" >& 2
+write_script fake_editor <<\EOF
+echo "$MSG" >"$1"
+echo "$MSG" >&2
EOF
-chmod a+x fake_editor.sh
-GIT_EDITOR=./fake_editor.sh
+GIT_EDITOR=./fake_editor
export GIT_EDITOR
+indent=" "
+
test_expect_success 'cannot annotate non-existing HEAD' '
test_must_fail env MSG=3 git notes add
'
-test_expect_success setup '
- : > a1 &&
- git add a1 &&
- test_tick &&
- git commit -m 1st &&
- : > a2 &&
- git add a2 &&
- test_tick &&
- git commit -m 2nd
+test_expect_success 'setup' '
+ test_commit 1st &&
+ test_commit 2nd
'
test_expect_success 'need valid notes ref' '
'
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_write_lines A B >expect &&
+ git show -s --format="A%n%NB" >actual &&
+ test_cmp expect actual
'
test_expect_success 'create notes' '
- git config core.notesRef refs/notes/commits &&
MSG=b4 git notes add &&
- test ! -f .git/NOTES_EDITMSG &&
- test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
- test b4 = $(git notes show) &&
+ test_path_is_missing .git/NOTES_EDITMSG &&
+ git ls-tree -r refs/notes/commits >actual &&
+ test_line_count = 1 actual &&
+ test "b4" = "$(git notes show)" &&
git show HEAD^ &&
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
+ test_write_lines A b4 B >expect &&
+ git show -s --format="A%n%NB" >actual &&
+ test_cmp expect actual
'
-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
+ cat <<-EOF >expect &&
+ a1d8fa6 refs/notes/commits@{0}: notes: Notes added by '\''git notes add'\''
+ EOF
+ git reflog show refs/notes/commits >actual &&
+ test_cmp expect actual
'
test_expect_success 'edit existing notes' '
MSG=b3 git notes edit &&
- test ! -f .git/NOTES_EDITMSG &&
- test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
- test b3 = $(git notes show) &&
+ test_path_is_missing .git/NOTES_EDITMSG &&
+ git ls-tree -r refs/notes/commits >actual &&
+ test_line_count = 1 actual &&
+ test "b3" = "$(git notes show)" &&
git show HEAD^ &&
test_must_fail git notes show HEAD^
'
test_expect_success 'cannot "git notes add -m" where notes already exists' '
test_must_fail git notes add -m "b2" &&
- test ! -f .git/NOTES_EDITMSG &&
- test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
- test b3 = $(git notes show) &&
+ test_path_is_missing .git/NOTES_EDITMSG &&
+ git ls-tree -r refs/notes/commits >actual &&
+ test_line_count = 1 actual &&
+ test "b3" = "$(git notes show)" &&
git show HEAD^ &&
test_must_fail git notes show HEAD^
'
test_expect_success 'can overwrite existing note with "git notes add -f -m"' '
git notes add -f -m "b1" &&
- test ! -f .git/NOTES_EDITMSG &&
- test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
- test b1 = $(git notes show) &&
+ test_path_is_missing .git/NOTES_EDITMSG &&
+ git ls-tree -r refs/notes/commits >actual &&
+ test_line_count = 1 actual &&
+ test "b1" = "$(git notes show)" &&
git show HEAD^ &&
test_must_fail git notes show HEAD^
'
test_expect_success 'add w/no options on existing note morphs into edit' '
MSG=b2 git notes add &&
- test ! -f .git/NOTES_EDITMSG &&
- test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
- test b2 = $(git notes show) &&
+ test_path_is_missing .git/NOTES_EDITMSG &&
+ git ls-tree -r refs/notes/commits >actual &&
+ test_line_count = 1 actual &&
+ test "b2" = "$(git notes show)" &&
git show HEAD^ &&
test_must_fail git notes show HEAD^
'
test_expect_success 'can overwrite existing note with "git notes add -f"' '
MSG=b1 git notes add -f &&
- test ! -f .git/NOTES_EDITMSG &&
- test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
- test b1 = $(git notes show) &&
+ test_path_is_missing .git/NOTES_EDITMSG &&
+ git ls-tree -r refs/notes/commits >actual &&
+ test_line_count = 1 actual &&
+ test "b1" = "$(git notes show)" &&
git show HEAD^ &&
test_must_fail git notes show HEAD^
'
-cat > expect << EOF
-commit 268048bfb8a1fb38e703baceb8ab235421bf80c5
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:14:13 2005 -0700
-
- 2nd
+test_expect_success 'show notes' '
+ cat >expect <<-EOF &&
+ commit 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:14:13 2005 -0700
-Notes:
- b1
-EOF
+ ${indent}2nd
-test_expect_success 'show notes' '
+ Notes:
+ ${indent}b1
+ EOF
! (git cat-file commit HEAD | grep b1) &&
- git log -1 > output &&
- test_cmp expect output
-'
-
-test_expect_success 'create multi-line notes (setup)' '
- : > a3 &&
- git add a3 &&
- test_tick &&
- git commit -m 3rd &&
- MSG="b3
-c3c3c3c3
-d3d3d3" git notes add
+ git log -1 >actual &&
+ test_cmp expect actual
'
-cat > expect-multiline << EOF
-commit 1584215f1d29c65e99c6c6848626553fdd07fd75
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:15:13 2005 -0700
-
- 3rd
+test_expect_success 'show multi-line notes' '
+ test_commit 3rd &&
+ MSG="b3${LF}c3c3c3c3${LF}d3d3d3" git notes add &&
+ cat >expect-multiline <<-EOF &&
+ commit d07d62e5208f22eb5695e7eb47667dc8b9860290
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:15:13 2005 -0700
-Notes:
- b3
- c3c3c3c3
- d3d3d3
-EOF
+ ${indent}3rd
-printf "\n" >> expect-multiline
-cat expect >> expect-multiline
+ Notes:
+ ${indent}b3
+ ${indent}c3c3c3c3
+ ${indent}d3d3d3
-test_expect_success 'show multi-line notes' '
- git log -2 > output &&
- test_cmp expect-multiline output
-'
-test_expect_success 'create -F notes (setup)' '
- : > a4 &&
- git add a4 &&
- test_tick &&
- git commit -m 4th &&
- echo "xyzzy" > note5 &&
- git notes add -F note5
+ EOF
+ cat expect >>expect-multiline &&
+ git log -2 >actual &&
+ test_cmp expect-multiline actual
'
-cat > expect-F << EOF
-commit 15023535574ded8b1a89052b32673f84cf9582b8
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:16:13 2005 -0700
+test_expect_success 'show -F notes' '
+ test_commit 4th &&
+ echo "xyzzy" >note5 &&
+ git notes add -F note5 &&
+ cat >expect-F <<-EOF &&
+ commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:16:13 2005 -0700
- 4th
+ ${indent}4th
-Notes:
- xyzzy
-EOF
+ Notes:
+ ${indent}xyzzy
-printf "\n" >> expect-F
-cat expect-multiline >> expect-F
-
-test_expect_success 'show -F notes' '
- git log -3 > output &&
- test_cmp expect-F output
+ EOF
+ cat expect-multiline >>expect-F &&
+ git log -3 >actual &&
+ test_cmp expect-F actual
'
test_expect_success 'Re-adding -F notes without -f fails' '
- echo "zyxxy" > note5 &&
+ echo "zyxxy" >note5 &&
test_must_fail git notes add -F note5 &&
- git log -3 > output &&
- test_cmp expect-F output
+ git log -3 >actual &&
+ test_cmp expect-F actual
'
-cat >expect << EOF
-commit 15023535574ded8b1a89052b32673f84cf9582b8
-tree e070e3af51011e47b183c33adf9736736a525709
-parent 1584215f1d29c65e99c6c6848626553fdd07fd75
-author A U Thor <author@example.com> 1112912173 -0700
-committer C O Mitter <committer@example.com> 1112912173 -0700
-
- 4th
-EOF
test_expect_success 'git log --pretty=raw does not show notes' '
- git log -1 --pretty=raw >output &&
- test_cmp expect output
+ cat >expect <<-EOF &&
+ commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+ tree 05ac65288c4c4b3b709a020ae94b2ece2f2201ae
+ parent d07d62e5208f22eb5695e7eb47667dc8b9860290
+ author A U Thor <author@example.com> 1112912173 -0700
+ committer C O Mitter <committer@example.com> 1112912173 -0700
+
+ ${indent}4th
+ EOF
+ git log -1 --pretty=raw >actual &&
+ test_cmp expect actual
'
-cat >>expect <<EOF
-
-Notes:
- xyzzy
-EOF
test_expect_success 'git log --show-notes' '
- git log -1 --pretty=raw --show-notes >output &&
- test_cmp expect output
+ cat >>expect <<-EOF &&
+
+ Notes:
+ ${indent}xyzzy
+ EOF
+ git log -1 --pretty=raw --show-notes >actual &&
+ test_cmp expect actual
'
test_expect_success 'git log --no-notes' '
- git log -1 --no-notes >output &&
- ! grep xyzzy output
+ git log -1 --no-notes >actual &&
+ ! grep xyzzy actual
'
test_expect_success 'git format-patch does not show notes' '
- git format-patch -1 --stdout >output &&
- ! grep xyzzy output
+ git format-patch -1 --stdout >actual &&
+ ! grep xyzzy actual
'
test_expect_success 'git format-patch --show-notes does show notes' '
- git format-patch --show-notes -1 --stdout >output &&
- grep xyzzy output
+ git format-patch --show-notes -1 --stdout >actual &&
+ grep xyzzy actual
'
for pretty in \
?*) p="$pretty" not=" not" negate="!" ;;
esac
test_expect_success "git show $pretty does$not show notes" '
- git show $p >output &&
- eval "$negate grep xyzzy output"
+ git show $p >actual &&
+ eval "$negate grep xyzzy actual"
'
done
'
test_expect_success 'git log --notes shows default notes' '
- git log -1 --notes >output &&
- grep xyzzy output &&
- ! grep alternate output
+ git log -1 --notes >actual &&
+ grep xyzzy actual &&
+ ! grep alternate actual
'
test_expect_success 'git log --notes=X shows only X' '
- git log -1 --notes=alternate >output &&
- ! grep xyzzy output &&
- grep alternate output
+ git log -1 --notes=alternate >actual &&
+ ! grep xyzzy actual &&
+ grep alternate actual
'
test_expect_success 'git log --notes --notes=X shows both' '
- git log -1 --notes --notes=alternate >output &&
- grep xyzzy output &&
- grep alternate output
+ git log -1 --notes --notes=alternate >actual &&
+ grep xyzzy actual &&
+ grep alternate actual
'
test_expect_success 'git log --no-notes resets default state' '
git log -1 --notes --notes=alternate \
--no-notes --notes=alternate \
- >output &&
- ! grep xyzzy output &&
- grep alternate output
+ >actual &&
+ ! grep xyzzy actual &&
+ grep alternate actual
'
test_expect_success 'git log --no-notes resets ref list' '
git log -1 --notes --notes=alternate \
--no-notes --notes \
- >output &&
- grep xyzzy output &&
- ! grep alternate output
-'
-
-test_expect_success 'create -m notes (setup)' '
- : > a5 &&
- git add a5 &&
- test_tick &&
- git commit -m 5th &&
- git notes add -m spam -m "foo
-bar
-baz"
-'
-
-whitespace=" "
-cat > expect-m << EOF
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:17:13 2005 -0700
-
- 5th
-
-Notes:
- spam
-$whitespace
- foo
- bar
- baz
-EOF
-
-printf "\n" >> expect-m
-cat expect-F >> expect-m
-
-test_expect_success 'show -m notes' '
- git log -4 > output &&
- test_cmp expect-m output
+ >actual &&
+ grep xyzzy actual &&
+ ! grep alternate actual
'
-test_expect_success 'remove note with add -f -F /dev/null (setup)' '
- git notes add -f -F /dev/null
-'
-
-cat > expect-rm-F << EOF
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:17:13 2005 -0700
-
- 5th
-EOF
-
-printf "\n" >> expect-rm-F
-cat expect-F >> expect-rm-F
-
-test_expect_success 'verify note removal with -F /dev/null' '
- git log -4 > output &&
- test_cmp expect-rm-F output &&
+test_expect_success 'show -m notes' '
+ test_commit 5th &&
+ git notes add -m spam -m "foo${LF}bar${LF}baz" &&
+ cat >expect-m <<-EOF &&
+ commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
+
+ ${indent}5th
+
+ Notes:
+ ${indent}spam
+ ${indent}
+ ${indent}foo
+ ${indent}bar
+ ${indent}baz
+
+ EOF
+ cat expect-F >>expect-m &&
+ git log -4 >actual &&
+ test_cmp expect-m actual
+'
+
+test_expect_success 'remove note with add -f -F /dev/null' '
+ git notes add -f -F /dev/null &&
+ cat >expect-rm-F <<-EOF &&
+ commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
+
+ ${indent}5th
+
+ EOF
+ cat expect-F >>expect-rm-F &&
+ git log -4 >actual &&
+ test_cmp expect-rm-F actual &&
test_must_fail git notes show
'
-test_expect_success 'do not create empty note with -m "" (setup)' '
- git notes add -m ""
-'
-
-test_expect_success 'verify non-creation of note with -m ""' '
- git log -4 > output &&
- test_cmp expect-rm-F output &&
+test_expect_success 'do not create empty note with -m ""' '
+ git notes add -m "" &&
+ git log -4 >actual &&
+ test_cmp expect-rm-F actual &&
test_must_fail git notes show
'
-cat > expect-combine_m_and_F << EOF
-foo
-
-xyzzy
+test_expect_success 'create note with combination of -m and -F' '
+ cat >expect-combine_m_and_F <<-EOF &&
+ foo
-bar
+ xyzzy
-zyxxy
+ bar
-baz
-EOF
+ zyxxy
-test_expect_success 'create note with combination of -m and -F' '
- echo "xyzzy" > note_a &&
- echo "zyxxy" > note_b &&
+ baz
+ EOF
+ echo "xyzzy" >note_a &&
+ echo "zyxxy" >note_b &&
git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" &&
- git notes show > output &&
- test_cmp expect-combine_m_and_F output
+ git notes show >actual &&
+ test_cmp expect-combine_m_and_F actual
'
-test_expect_success 'remove note with "git notes remove" (setup)' '
+test_expect_success 'remove note with "git notes remove"' '
git notes remove HEAD^ &&
- git notes remove
-'
-
-cat > expect-rm-remove << EOF
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:17:13 2005 -0700
+ git notes remove &&
+ cat >expect-rm-remove <<-EOF &&
+ commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
- 5th
+ ${indent}5th
-commit 15023535574ded8b1a89052b32673f84cf9582b8
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:16:13 2005 -0700
+ commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:16:13 2005 -0700
- 4th
-EOF
-
-printf "\n" >> expect-rm-remove
-cat expect-multiline >> expect-rm-remove
+ ${indent}4th
-test_expect_success 'verify note removal with "git notes remove"' '
- git log -4 > output &&
- test_cmp expect-rm-remove output &&
+ EOF
+ cat expect-multiline >>expect-rm-remove &&
+ git log -4 >actual &&
+ test_cmp expect-rm-remove actual &&
test_must_fail git notes show HEAD^
'
-cat > expect << EOF
-c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75
-c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5
-EOF
-
test_expect_success 'removing non-existing note should not create new commit' '
- git rev-parse --verify refs/notes/commits > before_commit &&
+ git rev-parse --verify refs/notes/commits >before_commit &&
test_must_fail git notes remove HEAD^ &&
- git rev-parse --verify refs/notes/commits > after_commit &&
+ git rev-parse --verify refs/notes/commits >after_commit &&
test_cmp before_commit after_commit
'
'
test_expect_success 'list notes with "git notes list"' '
- git notes list > output &&
- test_cmp expect output
+ cat >expect <<-EOF &&
+ c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+ c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290
+ EOF
+ git notes list >actual &&
+ test_cmp expect actual
'
test_expect_success 'list notes with "git notes"' '
- git notes > output &&
- test_cmp expect output
+ git notes >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-c18dc024e14f08d18d14eea0d747ff692d66d6a3
-EOF
-
test_expect_success 'list specific note with "git notes list <object>"' '
- git notes list HEAD^^ > output &&
- test_cmp expect output
+ cat >expect <<-EOF &&
+ c18dc024e14f08d18d14eea0d747ff692d66d6a3
+ EOF
+ git notes list HEAD^^ >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-EOF
-
test_expect_success 'listing non-existing notes fails' '
- test_must_fail git notes list HEAD > output &&
- test_cmp expect output
+ cat >expect <<-EOF &&
+ EOF
+ test_must_fail git notes list HEAD >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-Initial set of notes
-
-More notes appended with git notes append
-EOF
-
test_expect_success 'append to existing note with "git notes append"' '
+ cat >expect <<-EOF &&
+ Initial set of notes
+
+ More notes appended with git notes append
+ EOF
git notes add -m "Initial set of notes" &&
git notes append -m "More notes appended with git notes append" &&
- git notes show > output &&
- test_cmp expect output
+ git notes show >actual &&
+ test_cmp expect actual
'
-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
+ cat >expect_list <<-EOF &&
+ c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+ 4b6ad22357cc8a1296720574b8d2fbc22fab0671 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+ c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290
+ EOF
+ git notes list >actual &&
+ test_cmp expect_list actual
'
test_expect_success 'appending empty string does not change existing note' '
git notes append -m "" &&
- git notes show > output &&
- test_cmp expect output
+ git notes show >actual &&
+ test_cmp expect actual
'
test_expect_success 'git notes append == add when there is no existing note' '
git notes remove HEAD &&
test_must_fail git notes list HEAD &&
- git notes append -m "Initial set of notes
-
-More notes appended with git notes append" &&
- git notes show > output &&
- test_cmp expect output
+ git notes append -m "Initial set of notes${LF}${LF}More notes appended with git notes append" &&
+ git notes show >actual &&
+ test_cmp expect actual
'
test_expect_success 'appending empty string to non-existing note does not create note' '
'
test_expect_success 'create other note on a different notes ref (setup)' '
- : > a6 &&
- git add a6 &&
- test_tick &&
- git commit -m 6th &&
- GIT_NOTES_REF="refs/notes/other" git notes add -m "other note"
-'
+ test_commit 6th &&
+ GIT_NOTES_REF="refs/notes/other" git notes add -m "other note" &&
+ cat >expect-not-other <<-EOF &&
+ commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
-cat > expect-other << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:18:13 2005 -0700
-
- 6th
-
-Notes (other):
- other note
-EOF
+ ${indent}6th
+ EOF
+ cp expect-not-other expect-other &&
+ cat >>expect-other <<-EOF
-cat > expect-not-other << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:18:13 2005 -0700
-
- 6th
-EOF
+ Notes (other):
+ ${indent}other note
+ EOF
+'
test_expect_success 'Do not show note on other ref by default' '
- git log -1 > output &&
- test_cmp expect-not-other output
+ git log -1 >actual &&
+ test_cmp expect-not-other actual
'
test_expect_success 'Do show note when ref is given in GIT_NOTES_REF' '
- GIT_NOTES_REF="refs/notes/other" git log -1 > output &&
- test_cmp expect-other output
+ GIT_NOTES_REF="refs/notes/other" git log -1 >actual &&
+ test_cmp expect-other actual
'
test_expect_success 'Do show note when ref is given in core.notesRef config' '
- git config core.notesRef "refs/notes/other" &&
- git log -1 > output &&
- test_cmp expect-other output
+ test_config core.notesRef "refs/notes/other" &&
+ git log -1 >actual &&
+ test_cmp expect-other actual
'
test_expect_success 'Do not show note when core.notesRef is overridden' '
- GIT_NOTES_REF="refs/notes/wrong" git log -1 > output &&
- test_cmp expect-not-other output
+ test_config core.notesRef "refs/notes/other" &&
+ GIT_NOTES_REF="refs/notes/wrong" git log -1 >actual &&
+ test_cmp expect-not-other actual
'
-cat > expect-both << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:18:13 2005 -0700
-
- 6th
+test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
+ cat >expect-both <<-EOF &&
+ commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
-Notes:
- order test
+ ${indent}6th
-Notes (other):
- other note
+ Notes:
+ ${indent}order test
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:17:13 2005 -0700
+ Notes (other):
+ ${indent}other note
- 5th
+ commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
-Notes:
- replacement for deleted note
-EOF
+ ${indent}5th
-test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
+ Notes:
+ ${indent}replacement for deleted note
+ EOF
GIT_NOTES_REF=refs/notes/commits git notes add \
-m"replacement for deleted note" HEAD^ &&
GIT_NOTES_REF=refs/notes/commits git notes add -m"order test" &&
- git config --unset core.notesRef &&
- git config notes.displayRef "refs/notes/*" &&
- git log -2 > output &&
- test_cmp expect-both output
+ test_unconfig core.notesRef &&
+ test_config notes.displayRef "refs/notes/*" &&
+ git log -2 >actual &&
+ test_cmp expect-both actual
'
test_expect_success 'core.notesRef is implicitly in notes.displayRef' '
- git config core.notesRef refs/notes/commits &&
- git config notes.displayRef refs/notes/other &&
- git log -2 > output &&
- test_cmp expect-both output
+ test_config core.notesRef refs/notes/commits &&
+ test_config notes.displayRef refs/notes/other &&
+ git log -2 >actual &&
+ test_cmp expect-both actual
'
test_expect_success 'notes.displayRef can be given more than once' '
- git config --unset core.notesRef &&
- git config notes.displayRef refs/notes/commits &&
+ test_unconfig core.notesRef &&
+ test_config notes.displayRef refs/notes/commits &&
git config --add notes.displayRef refs/notes/other &&
- git log -2 > output &&
- test_cmp expect-both output
+ git log -2 >actual &&
+ test_cmp expect-both actual
'
-cat > expect-both-reversed << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:18:13 2005 -0700
-
- 6th
+test_expect_success 'notes.displayRef respects order' '
+ cat >expect-both-reversed <<-EOF &&
+ commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
-Notes (other):
- other note
+ ${indent}6th
-Notes:
- order test
-EOF
+ Notes (other):
+ ${indent}other note
-test_expect_success 'notes.displayRef respects order' '
- git config core.notesRef refs/notes/other &&
- git config --unset-all notes.displayRef &&
- git config notes.displayRef refs/notes/commits &&
- git log -1 > output &&
- test_cmp expect-both-reversed output
+ Notes:
+ ${indent}order test
+ EOF
+ test_config core.notesRef refs/notes/other &&
+ test_config notes.displayRef refs/notes/commits &&
+ git log -1 >actual &&
+ test_cmp expect-both-reversed actual
'
test_expect_success 'GIT_NOTES_DISPLAY_REF works' '
- git config --unset-all core.notesRef &&
- git config --unset-all notes.displayRef &&
GIT_NOTES_DISPLAY_REF=refs/notes/commits:refs/notes/other \
- git log -2 > output &&
- test_cmp expect-both output
+ git log -2 >actual &&
+ test_cmp expect-both actual
'
-cat > expect-none << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:18:13 2005 -0700
-
- 6th
+test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '
+ cat >expect-none <<-EOF &&
+ commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:17:13 2005 -0700
+ ${indent}6th
- 5th
-EOF
+ commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:17:13 2005 -0700
-test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '
- git config notes.displayRef "refs/notes/*" &&
- GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 > output &&
- test_cmp expect-none output
+ ${indent}5th
+ EOF
+ test_config notes.displayRef "refs/notes/*" &&
+ GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 >actual &&
+ test_cmp expect-none actual
'
test_expect_success '--show-notes=* adds to GIT_NOTES_DISPLAY_REF' '
- GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 > output &&
- test_cmp expect-both output
+ GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 >actual &&
+ test_cmp expect-both actual
'
-cat > expect-commits << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:18:13 2005 -0700
-
- 6th
+test_expect_success '--no-standard-notes' '
+ cat >expect-commits <<EOF
+ commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:18:13 2005 -0700
-Notes:
- order test
-EOF
+ ${indent}6th
-test_expect_success '--no-standard-notes' '
- git log --no-standard-notes --show-notes=commits -1 > output &&
- test_cmp expect-commits output
+ Notes:
+ ${indent}order test
+ EOF
+ git log --no-standard-notes --show-notes=commits -1 >actual &&
+ test_cmp expect-commits actual
'
test_expect_success '--standard-notes' '
+ test_config notes.displayRef "refs/notes/*" &&
git log --no-standard-notes --show-notes=commits \
- --standard-notes -2 > output &&
- test_cmp expect-both output
+ --standard-notes -2 >actual &&
+ test_cmp expect-both actual
'
test_expect_success '--show-notes=ref accumulates' '
git log --show-notes=other --show-notes=commits \
- --no-standard-notes -1 > output &&
- test_cmp expect-both-reversed output
+ --no-standard-notes -1 >actual &&
+ test_cmp expect-both-reversed actual
'
test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
- git config core.notesRef refs/notes/other &&
- echo "Note on a tree" > expect &&
+ test_config core.notesRef refs/notes/other &&
+ echo "Note on a tree" >expect &&
git notes add -m "Note on a tree" HEAD: &&
- git notes show HEAD: > actual &&
+ git notes show HEAD: >actual &&
test_cmp expect actual &&
- echo "Note on a blob" > expect &&
+ echo "Note on a blob" >expect &&
filename=$(git ls-tree --name-only HEAD | head -n1) &&
git notes add -m "Note on a blob" HEAD:$filename &&
- git notes show HEAD:$filename > actual &&
+ git notes show HEAD:$filename >actual &&
test_cmp expect actual &&
- echo "Note on a tag" > expect &&
+ echo "Note on a tag" >expect &&
git tag -a -m "This is an annotated tag" foobar HEAD^ &&
git notes add -m "Note on a tag" foobar &&
- git notes show foobar > actual &&
+ git notes show foobar >actual &&
test_cmp expect actual
'
-cat > expect << EOF
-commit 2ede89468182a62d0bde2583c736089bcf7d7e92
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:19:13 2005 -0700
-
- 7th
+test_expect_success 'create note from other note with "git notes add -C"' '
+ cat >expect <<-EOF &&
+ commit fb01e0ca8c33b6cc0c6451dde747f97df567cb5c
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:19:13 2005 -0700
-Notes (other):
- other note
-EOF
+ ${indent}7th
-test_expect_success 'create note from other note with "git notes add -C"' '
- : > a7 &&
- git add a7 &&
- test_tick &&
- git commit -m 7th &&
+ Notes:
+ ${indent}order test
+ EOF
+ test_commit 7th &&
git notes add -C $(git notes list HEAD^) &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual &&
test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
'
test_expect_success 'create note from non-existing note with "git notes add -C" fails' '
- : > a8 &&
- git add a8 &&
- test_tick &&
- git commit -m 8th &&
+ test_commit 8th &&
test_must_fail git notes add -C deadbeef &&
test_must_fail git notes list HEAD
'
test_must_fail git notes list HEAD
'
-cat > expect << EOF
-commit 80d796defacd5db327b7a4e50099663902fbdc5c
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:20:13 2005 -0700
-
- 8th
+test_expect_success 'create note from blob with "git notes add -C" reuses blob id' '
+ cat >expect <<-EOF &&
+ commit 9a4c31c7f722b5d517e92c64e932dd751e1413bf
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:20:13 2005 -0700
-Notes (other):
- This is a blob object
-EOF
+ ${indent}8th
-test_expect_success 'create note from blob with "git notes add -C" reuses blob id' '
+ Notes:
+ ${indent}This is a blob object
+ EOF
blob=$(echo "This is a blob object" | git hash-object -w --stdin) &&
git notes add -C $blob &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual &&
test "$(git notes list HEAD)" = "$blob"
'
-cat > expect << EOF
-commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:21:13 2005 -0700
-
- 9th
+test_expect_success 'create note from other note with "git notes add -c"' '
+ cat >expect <<-EOF &&
+ commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:21:13 2005 -0700
-Notes (other):
- yet another note
-EOF
+ ${indent}9th
-test_expect_success 'create note from other note with "git notes add -c"' '
- : > a9 &&
- git add a9 &&
- test_tick &&
- git commit -m 9th &&
+ Notes:
+ ${indent}yet another note
+ EOF
+ test_commit 9th &&
MSG="yet another note" git notes add -c $(git notes list HEAD^^) &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual
'
test_expect_success 'create note from non-existing note with "git notes add -c" fails' '
- : > a10 &&
- git add a10 &&
- test_tick &&
- git commit -m 10th &&
+ test_commit 10th &&
test_must_fail env MSG="yet another note" git notes add -c deadbeef &&
test_must_fail git notes list HEAD
'
-cat > expect << EOF
-commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:21:13 2005 -0700
-
- 9th
-
-Notes (other):
- yet another note
-$whitespace
- yet another note
-EOF
-
test_expect_success 'append to note from other note with "git notes append -C"' '
+ cat >expect <<-EOF &&
+ commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:21:13 2005 -0700
+
+ ${indent}9th
+
+ Notes:
+ ${indent}yet another note
+ ${indent}
+ ${indent}yet another note
+ EOF
git notes append -C $(git notes list HEAD^) HEAD^ &&
- git log -1 HEAD^ > actual &&
+ git log -1 HEAD^ >actual &&
test_cmp expect actual
'
-cat > expect << EOF
-commit ffed603236bfa3891c49644257a83598afe8ae5a
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:22:13 2005 -0700
+test_expect_success 'create note from other note with "git notes append -c"' '
+ cat >expect <<-EOF &&
+ commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:22:13 2005 -0700
- 10th
+ ${indent}10th
-Notes (other):
- other note
-EOF
-
-test_expect_success 'create note from other note with "git notes append -c"' '
+ Notes:
+ ${indent}other note
+ EOF
MSG="other note" git notes append -c $(git notes list HEAD^) &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual
'
-cat > expect << EOF
-commit ffed603236bfa3891c49644257a83598afe8ae5a
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:22:13 2005 -0700
-
- 10th
-
-Notes (other):
- other note
-$whitespace
- yet another note
-EOF
-
test_expect_success 'append to note from other note with "git notes append -c"' '
+ cat >expect <<-EOF &&
+ commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:22:13 2005 -0700
+
+ ${indent}10th
+
+ Notes:
+ ${indent}other note
+ ${indent}
+ ${indent}yet another note
+ EOF
MSG="yet another note" git notes append -c $(git notes list HEAD) &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual
'
-cat > expect << EOF
-commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:23:13 2005 -0700
-
- 11th
-
-Notes (other):
- other note
-$whitespace
- yet another note
-EOF
-
test_expect_success 'copy note with "git notes copy"' '
- : > a11 &&
- git add a11 &&
- test_tick &&
- git commit -m 11th &&
+ cat >expect <<-EOF &&
+ commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:23:13 2005 -0700
+
+ ${indent}11th
+
+ Notes:
+ ${indent}other note
+ ${indent}
+ ${indent}yet another note
+ EOF
+ test_commit 11th &&
git notes copy HEAD^ HEAD &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual &&
test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
'
test_expect_success 'prevent overwrite with "git notes copy"' '
test_must_fail git notes copy HEAD~2 HEAD &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual &&
test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
'
-cat > expect << EOF
-commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:23:13 2005 -0700
-
- 11th
-
-Notes (other):
- yet another note
-$whitespace
- yet another note
-EOF
-
test_expect_success 'allow overwrite with "git notes copy -f"' '
+ cat >expect <<-EOF &&
+ commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:23:13 2005 -0700
+
+ ${indent}11th
+
+ Notes:
+ ${indent}yet another note
+ ${indent}
+ ${indent}yet another note
+ EOF
git notes copy -f HEAD~2 HEAD &&
- git log -1 > actual &&
+ git log -1 >actual &&
test_cmp expect actual &&
test "$(git notes list HEAD)" = "$(git notes list HEAD~2)"
'
test_expect_success 'cannot copy note from object without notes' '
- : > a12 &&
- git add a12 &&
- test_tick &&
- git commit -m 12th &&
- : > a13 &&
- git add a13 &&
- test_tick &&
- git commit -m 13th &&
+ test_commit 12th &&
+ test_commit 13th &&
test_must_fail git notes copy HEAD^ HEAD
'
-cat > expect << EOF
-commit e5d4fb5698d564ab8c73551538ecaf2b0c666185
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:25:13 2005 -0700
-
- 13th
+test_expect_success 'git notes copy --stdin' '
+ cat >expect <<-EOF &&
+ commit e871aa61182b1d95d0a6fb75445d891722863b6b
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:25:13 2005 -0700
-Notes (other):
- yet another note
-$whitespace
- yet another note
+ ${indent}13th
-commit 7038787dfe22a14c3867ce816dbba39845359719
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:24:13 2005 -0700
+ Notes:
+ ${indent}yet another note
+ ${indent}
+ ${indent}yet another note
- 12th
+ commit 65e263ded02ae4e8839bc151095113737579dc12
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:24:13 2005 -0700
-Notes (other):
- other note
-$whitespace
- yet another note
-EOF
+ ${indent}12th
-test_expect_success 'git notes copy --stdin' '
+ Notes:
+ ${indent}other note
+ ${indent}
+ ${indent}yet another note
+ EOF
(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
git notes copy --stdin &&
- git log -2 > output &&
- test_cmp expect output &&
+ git log -2 >actual &&
+ test_cmp expect actual &&
test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" &&
test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)"
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
-
- 15th
+test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
-commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:26:13 2005 -0700
+ ${indent}15th
- 14th
-EOF
+ commit 07c85d77059393ed0154b8c96906547a59dfcddd
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:26:13 2005 -0700
-test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
+ ${indent}14th
+ EOF
test_commit 14th &&
test_commit 15th &&
(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
git notes copy --for-rewrite=foo &&
- git log -2 > output &&
- test_cmp expect output
+ git log -2 >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
-
- 15th
-
-Notes (other):
- yet another note
-$whitespace
- yet another note
-
-commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:26:13 2005 -0700
-
- 14th
-
-Notes (other):
- other note
-$whitespace
- yet another note
-EOF
-
test_expect_success 'git notes copy --for-rewrite (enabled)' '
- git config notes.rewriteMode overwrite &&
- git config notes.rewriteRef "refs/notes/*" &&
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
+
+ ${indent}15th
+
+ Notes:
+ ${indent}yet another note
+ ${indent}
+ ${indent}yet another note
+
+ commit 07c85d77059393ed0154b8c96906547a59dfcddd
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:26:13 2005 -0700
+
+ ${indent}14th
+
+ Notes:
+ ${indent}other note
+ ${indent}
+ ${indent}yet another note
+ EOF
+ test_config notes.rewriteMode overwrite &&
+ test_config notes.rewriteRef "refs/notes/*" &&
(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
git notes copy --for-rewrite=foo &&
- git log -2 > output &&
- test_cmp expect output
+ git log -2 >actual &&
+ test_cmp expect actual
'
test_expect_success 'git notes copy --for-rewrite (disabled)' '
- git config notes.rewrite.bar false &&
+ test_config notes.rewrite.bar false &&
echo $(git rev-parse HEAD~3) $(git rev-parse HEAD) |
git notes copy --for-rewrite=bar &&
- git log -2 > output &&
- test_cmp expect output
+ git log -2 >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
-
- 15th
+test_expect_success 'git notes copy --for-rewrite (overwrite)' '
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
-Notes (other):
- a fresh note
-EOF
+ ${indent}15th
-test_expect_success 'git notes copy --for-rewrite (overwrite)' '
+ Notes:
+ ${indent}a fresh note
+ EOF
git notes add -f -m"a fresh note" HEAD^ &&
+ test_config notes.rewriteMode overwrite &&
+ test_config notes.rewriteRef "refs/notes/*" &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
test_expect_success 'git notes copy --for-rewrite (ignore)' '
- git config notes.rewriteMode ignore &&
+ test_config notes.rewriteMode ignore &&
+ test_config notes.rewriteRef "refs/notes/*" &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
-
- 15th
-
-Notes (other):
- a fresh note
-$whitespace
- another fresh note
-EOF
-
test_expect_success 'git notes copy --for-rewrite (append)' '
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
+
+ ${indent}15th
+
+ Notes:
+ ${indent}a fresh note
+ ${indent}
+ ${indent}another fresh note
+ EOF
git notes add -f -m"another fresh note" HEAD^ &&
- git config notes.rewriteMode concatenate &&
+ test_config notes.rewriteMode concatenate &&
+ test_config notes.rewriteRef "refs/notes/*" &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
-
- 15th
-
-Notes (other):
- a fresh note
-$whitespace
- another fresh note
-$whitespace
- append 1
-$whitespace
- append 2
-EOF
-
test_expect_success 'git notes copy --for-rewrite (append two to one)' '
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
+
+ ${indent}15th
+
+ Notes:
+ ${indent}a fresh note
+ ${indent}
+ ${indent}another fresh note
+ ${indent}
+ ${indent}append 1
+ ${indent}
+ ${indent}append 2
+ EOF
git notes add -f -m"append 1" HEAD^ &&
git notes add -f -m"append 2" HEAD^^ &&
+ test_config notes.rewriteMode concatenate &&
+ test_config notes.rewriteRef "refs/notes/*" &&
(echo $(git rev-parse HEAD^) $(git rev-parse HEAD);
echo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) |
git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
test_expect_success 'git notes copy --for-rewrite (append empty)' '
git notes remove HEAD^ &&
+ test_config notes.rewriteMode concatenate &&
+ test_config notes.rewriteRef "refs/notes/*" &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
-
- 15th
-
-Notes (other):
- replacement note 1
-EOF
-
test_expect_success 'GIT_NOTES_REWRITE_MODE works' '
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
+
+ ${indent}15th
+
+ Notes:
+ ${indent}replacement note 1
+ EOF
+ test_config notes.rewriteMode concatenate &&
+ test_config notes.rewriteRef "refs/notes/*" &&
git notes add -f -m"replacement note 1" HEAD^ &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date: Thu Apr 7 15:27:13 2005 -0700
+test_expect_success 'GIT_NOTES_REWRITE_REF works' '
+ cat >expect <<-EOF &&
+ commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:27:13 2005 -0700
- 15th
+ ${indent}15th
-Notes (other):
- replacement note 2
-EOF
-
-test_expect_success 'GIT_NOTES_REWRITE_REF works' '
- git config notes.rewriteMode overwrite &&
+ Notes:
+ ${indent}replacement note 2
+ EOF
git notes add -f -m"replacement note 2" HEAD^ &&
- git config --unset-all notes.rewriteRef &&
+ test_config notes.rewriteMode overwrite &&
+ test_unconfig notes.rewriteRef &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
GIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \
git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' '
- git config notes.rewriteRef refs/notes/other &&
git notes add -f -m"replacement note 3" HEAD^ &&
+ test_config notes.rewriteMode overwrite &&
+ test_config notes.rewriteRef refs/notes/other &&
echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
GIT_NOTES_REWRITE_REF= git notes copy --for-rewrite=foo &&
- git log -1 > output &&
- test_cmp expect output
+ git log -1 >actual &&
+ test_cmp expect actual
'
test_expect_success 'git notes copy diagnoses too many or too few parameters' '
'
test_expect_success 'git notes get-ref (no overrides)' '
- git config --unset core.notesRef &&
+ test_unconfig core.notesRef &&
sane_unset GIT_NOTES_REF &&
test "$(git notes get-ref)" = "refs/notes/commits"
'
test_expect_success 'git notes get-ref (core.notesRef)' '
- git config core.notesRef refs/notes/foo &&
+ test_config core.notesRef refs/notes/foo &&
test "$(git notes get-ref)" = "refs/notes/foo"
'
test "$(GIT_NOTES_REF=refs/notes/bar git notes --ref=baz get-ref)" = "refs/notes/baz"
'
+test_expect_success 'setup testing of empty notes' '
+ test_unconfig core.notesRef &&
+ test_commit 16th &&
+ empty_blob=$(git hash-object -w /dev/null) &&
+ echo "$empty_blob" >expect_empty
+'
+
+while read cmd
+do
+ test_expect_success "'git notes $cmd' removes empty note" "
+ test_might_fail git notes remove HEAD &&
+ MSG= git notes $cmd &&
+ test_must_fail git notes list HEAD
+ "
+
+ test_expect_success "'git notes $cmd --allow-empty' stores empty note" "
+ test_might_fail git notes remove HEAD &&
+ MSG= git notes $cmd --allow-empty &&
+ git notes list HEAD >actual &&
+ test_cmp expect_empty actual
+ "
+done <<\EOF
+add
+add -F /dev/null
+add -m ""
+add -c "$empty_blob"
+add -C "$empty_blob"
+append
+append -F /dev/null
+append -m ""
+append -c "$empty_blob"
+append -C "$empty_blob"
+edit
+EOF
+
+test_expect_success 'empty notes are displayed by git log' '
+ test_commit 17th &&
+ git log -1 >expect &&
+ cat >>expect <<-EOF &&
+
+ Notes:
+ EOF
+ git notes add -C "$empty_blob" --allow-empty &&
+ git log -1 >actual &&
+ test_cmp expect actual
+'
+
test_done
test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
pristine_detach initial &&
test_must_fail git cherry-pick picked &&
+
git commit -a -s &&
- pwd &&
- cat <<EOF > expected &&
-picked
-Signed-off-by: C O Mitter <committer@example.com>
+ # Do S-o-b and Conflicts appear in the right order?
+ cat <<-\EOF >expect &&
+ Signed-off-by: C O Mitter <committer@example.com>
+ # Conflicts:
+ EOF
+ grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+ test_cmp expect actual &&
+
+ cat <<-\EOF >expected &&
+ picked
-Conflicts:
- foo
-EOF
+ Signed-off-by: C O Mitter <committer@example.com>
+ EOF
- git show -s --pretty=format:%B > actual &&
+ git show -s --pretty=format:%B >actual &&
test_cmp expected actual
'
+test_expect_success 'commit --amend -s places the sign-off at the right place' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick picked &&
+
+ # emulate old-style conflicts block
+ mv .git/MERGE_MSG .git/MERGE_MSG+ &&
+ sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
+
+ git commit -a &&
+ git commit --amend -s &&
+
+ # Do S-o-b and Conflicts appear in the right order?
+ cat <<-\EOF >expect &&
+ Signed-off-by: C O Mitter <committer@example.com>
+ Conflicts:
+ EOF
+ grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+ test_cmp expect actual
+'
+
test_done
! (git ls-files | grep "\\.ig")
'
+test_expect_success 'error out when attempting to add ignored ones but add others' '
+ touch a.if &&
+ test_must_fail git add a.?? &&
+ ! (git ls-files | grep "\\.ig") &&
+ (git ls-files | grep a.if)
+'
+
test_expect_success 'add ignored ones with -f' '
git add -f a.?? &&
git ls-files --error-unmatch a.ig
The following paths are ignored by one of your .gitignore files:
ignored-file
Use -f if you really want to add them.
-fatal: no files added
EOF
cat >expect.out <<\EOF
add 'track-this'
color "254 bold 255" "[1;38;5;254;48;5;255m"
'
+test_expect_success '"normal" yields no color at all"' '
+ color "normal black" "[40m"
+'
+
+test_expect_success '-1 is a synonym for "normal"' '
+ color "-1 black" "[40m"
+'
+
test_expect_success 'color too small' '
invalid_color "-2"
'
git format-patch --stdout first >patch1 &&
{
+ echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
echo "X-Fake-Field: Line One" &&
echo "X-Fake-Field: Line Two" &&
echo "X-Fake-Field: Line Three" &&
test_i18ncmp expected actual
'
+test_expect_success 'am --message-id really adds the message id' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout HEAD^ &&
+ git am --message-id patch1.eml &&
+ test_path_is_missing .git/rebase-apply &&
+ git cat-file commit HEAD | tail -n1 >actual &&
+ grep Message-Id patch1.eml >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'am --message-id -s signs off after the message id' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout HEAD^ &&
+ git am -s --message-id patch1.eml &&
+ test_path_is_missing .git/rebase-apply &&
+ git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
+ grep Message-Id patch1.eml >expected &&
+ test_cmp expected actual
+'
+
test_done
ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten &&
echo long filename >a/four$hundred &&
mkdir a/bin &&
- cp /bin/sh a/bin &&
+ test-genrandom "frotz" 500000 >a/bin/sh &&
printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
printf "A not substituted O" >a/substfile2 &&
if test_have_prereq SYMLINKS; then
then
check_mailinfo $mail --no-inbody-headers
fi
+ if test -f "$TEST_DIRECTORY"/t5100/msg$mail--message-id
+ then
+ check_mailinfo $mail --message-id
+ fi
'
done
--- /dev/null
+Author: Dmitriy Blinov
+Email: bda@mnsspb.ru
+Subject: Изменён список пакетов необходимых для сборки
+Date: Wed, 12 Nov 2008 17:54:41 +0300
+
--- /dev/null
+textlive-* исправлены на texlive-*
+docutils заменён на python-docutils
+
+Действительно, оказалось, что rest2web вытягивает за собой
+python-docutils. В то время как сам rest2web не нужен.
+
+Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru>
+Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
--- /dev/null
+---
+ howto/build_navy.txt | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/howto/build_navy.txt b/howto/build_navy.txt
+index 3fd3afb..0ee807e 100644
+--- a/howto/build_navy.txt
++++ b/howto/build_navy.txt
+@@ -119,8 +119,8 @@
+ - libxv-dev
+ - libusplash-dev
+ - latex-make
+- - textlive-lang-cyrillic
+- - textlive-latex-extra
++ - texlive-lang-cyrillic
++ - texlive-latex-extra
+ - dia
+ - python-pyrex
+ - libtool
+@@ -128,7 +128,7 @@
+ - sox
+ - cython
+ - imagemagick
+- - docutils
++ - python-docutils
+
+ #. на машине dinar: добавить свой открытый ssh-ключ в authorized_keys2 пользователя ddev
+ #. на своей машине: отредактировать /etc/sudoers (команда ``visudo``) примерно следующим образом::
+--
+1.5.6.5
)
'
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+ git push testrepo master &&
+ (
+ cd testrepo &&
+ git reset --hard &&
+ git config receive.denyCurrentBranch updateInstead
+ ) &&
+ test_commit third path2 &&
+
+ # Try pushing into a repository with pristine working tree
+ git push testrepo master &&
+ (
+ cd testrepo &&
+ git update-index -q --refresh &&
+ git diff-files --quiet -- &&
+ git diff-index --quiet --cached HEAD -- &&
+ test third = "$(cat path2)" &&
+ test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+ ) &&
+
+ # Try pushing into a repository with working tree needing a refresh
+ (
+ cd testrepo &&
+ git reset --hard HEAD^ &&
+ test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+ test-chmtime +100 path1
+ ) &&
+ git push testrepo master &&
+ (
+ cd testrepo &&
+ git update-index -q --refresh &&
+ git diff-files --quiet -- &&
+ git diff-index --quiet --cached HEAD -- &&
+ test_cmp ../path1 path1 &&
+ test third = "$(cat path2)" &&
+ test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+ ) &&
+
+ # Update what is to be pushed
+ test_commit fourth path2 &&
+
+ # Try pushing into a repository with a dirty working tree
+ # (1) the working tree updated
+ (
+ cd testrepo &&
+ echo changed >path1
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+ git diff --quiet --cached &&
+ test changed = "$(cat path1)"
+ ) &&
+
+ # (2) the index updated
+ (
+ cd testrepo &&
+ echo changed >path1 &&
+ git add path1
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+ git diff --quiet &&
+ test changed = "$(cat path1)"
+ ) &&
+
+ # Introduce a new file in the update
+ test_commit fifth path3 &&
+
+ # (3) the working tree has an untracked file that would interfere
+ (
+ cd testrepo &&
+ git reset --hard &&
+ echo changed >path3
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+ git diff --quiet &&
+ git diff --quiet --cached &&
+ test changed = "$(cat path3)"
+ ) &&
+
+ # (4) the target changes to what gets pushed but it still is a change
+ (
+ cd testrepo &&
+ git reset --hard &&
+ echo fifth >path3 &&
+ git add path3
+ ) &&
+ test_must_fail git push testrepo master &&
+ (
+ cd testrepo &&
+ test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+ git diff --quiet &&
+ test fifth = "$(cat path3)"
+ )
+
+'
+
test_done
# $2 = expected target branch for the push
# $3 = [optional] repo to check for actual output (repo1 by default)
test_push_success () {
- git -c push.default="$1" push &&
+ git ${1:+-c push.default="$1"} push &&
check_pushed_commit HEAD "$2" "$3"
}
# check that push fails and does not modify any remote branch
test_push_failure () {
git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect &&
- test_must_fail git -c push.default="$1" push &&
+ test_must_fail git ${1:+-c push.default="$1"} push &&
git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual &&
test_cmp expect actual
}
# master is updated (parent2 does not have foo)
test_pushdefault_workflow success matching master triangular
+# default tests, when no push-default is specified. This
+# should behave the same as "simple" in non-triangular
+# settings, and as "current" otherwise.
+
+test_expect_success 'default behavior allows "simple" push' '
+ test_config branch.master.remote parent1 &&
+ test_config branch.master.merge refs/heads/master &&
+ test_config remote.pushdefault parent1 &&
+ test_commit default-master-master &&
+ test_push_success "" master
+'
+
+test_expect_success 'default behavior rejects non-simple push' '
+ test_config branch.master.remote parent1 &&
+ test_config branch.master.merge refs/heads/foo &&
+ test_config remote.pushdefault parent1 &&
+ test_commit default-master-foo &&
+ test_push_failure ""
+'
+
+test_expect_success 'default triangular behavior acts like "current"' '
+ test_config branch.master.remote parent1 &&
+ test_config branch.master.merge refs/heads/foo &&
+ test_config remote.pushdefault parent2 &&
+ test_commit default-triangular &&
+ test_push_success "" master repo2
+'
+
test_done
'
test_expect_success 'with message that has comments' '
- cat basic_message >>message_with_comments &&
+ cat basic_message >message_with_comments &&
sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
# comment
Reviewed-by: Johan
Cc: Peff
+ # last comment
+
EOF
cat basic_patch >>expected &&
git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
test_cmp expected actual
'
+test_expect_success 'with message that has an old style conflict block' '
+ cat basic_message >message_with_comments &&
+ sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
+ # comment
+
+ # other comment
+ Cc: Z
+ # yet another comment
+ Reviewed-by: Johan
+ Reviewed-by: Z
+ # last comment
+
+ Conflicts:
+
+ EOF
+ cat basic_message >expected &&
+ cat >>expected <<-\EOF &&
+ # comment
+
+ Reviewed-by: Johan
+ Cc: Peff
+ # last comment
+
+ Conflicts:
+
+ EOF
+ git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'with commit complex message and trailer args' '
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
test_cmp expected actual
'
+test_expect_success $PREREQ 'setup expect' '
+cat >email-using-8bit <<EOF
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+Message-Id: <bogus-message-id@example.com>
+From: A U Thor <author@example.com>
+Date: Sat, 12 Jun 2010 15:53:58 +0200
+Content-Type: text/plain; charset=UTF-8
+Subject: Nothing to see here.
+
+Dieser Betreff enthält auch einen Umlaut!
+EOF
+'
+
+test_expect_success $PREREQ 'sendemail.transferencoding=7bit fails on 8bit data' '
+ clean_fake_sendmail &&
+ git config sendemail.transferEncoding 7bit &&
+ test_must_fail git send-email \
+ --transfer-encoding=7bit \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ grep "cannot send message as 7bit" errors &&
+ test -z "$(ls msgtxt*)"
+'
+
+test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEncoding' '
+ clean_fake_sendmail &&
+ git config sendemail.transferEncoding 8bit
+ test_must_fail git send-email \
+ --transfer-encoding=7bit \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ grep "cannot send message as 7bit" errors &&
+ test -z "$(ls msgtxt*)"
+'
+
+test_expect_success $PREREQ 'sendemail.transferencoding=8bit' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=8bit \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ sed '1,/^$/d' email-using-8bit >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+cat >expected <<EOF
+Dieser Betreff enth=C3=A4lt auch einen Umlaut!
+EOF
+'
+
+test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printable' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=quoted-printable \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+cat >expected <<EOF
+RGllc2VyIEJldHJlZmYgZW50aMOkbHQgYXVjaCBlaW5lbiBVbWxhdXQhCg==
+EOF
+'
+
+test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=base64 \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-8bit \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+cat >email-using-qp <<EOF
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+Message-Id: <bogus-message-id@example.com>
+From: A U Thor <author@example.com>
+Date: Sat, 12 Jun 2010 15:53:58 +0200
+MIME-Version: 1.0
+Content-Transfer-Encoding: quoted-printable
+Content-Type: text/plain; charset=UTF-8
+Subject: Nothing to see here.
+
+Dieser Betreff enth=C3=A4lt auch einen Umlaut!
+EOF
+'
+
+test_expect_success $PREREQ 'convert from quoted-printable to base64' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=base64 \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-qp \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' "
+tr -d '\\015' | tr '%' '\\015' > email-using-crlf <<EOF
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+Message-Id: <bogus-message-id@example.com>
+From: A U Thor <author@example.com>
+Date: Sat, 12 Jun 2010 15:53:58 +0200
+Content-Type: text/plain; charset=UTF-8
+Subject: Nothing to see here.
+
+Look, I have a CRLF and an = sign!%
+EOF
+"
+
+test_expect_success $PREREQ 'setup expect' '
+cat >expected <<EOF
+Look, I have a CRLF and an =3D sign!=0D
+EOF
+'
+
+test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printable' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=quoted-printable \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-crlf \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+cat >expected <<EOF
+TG9vaywgSSBoYXZlIGEgQ1JMRiBhbmQgYW4gPSBzaWduIQ0K
+EOF
+'
+
+test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '
+ clean_fake_sendmail &&
+ git send-email \
+ --transfer-encoding=base64 \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ email-using-crlf \
+ 2>errors >out &&
+ sed '1,/^$/d' msgtxt1 >actual &&
+ test_cmp expected actual
+'
+
+
# Note that the patches in this test are deliberately out of order; we
# want to make sure it works even if the cover-letter is not in the
# first mail.
setup_cvs_test_repository t9603
-test_expect_failure 'import with criss cross times on revisions' '
+test_expect_failure PERL 'import with criss cross times on revisions' '
git cvsimport -p"-x" -C module-git module &&
(cd module-git &&
setup_cvs_test_repository t9604
-test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' '
+test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' '
TZ=CST6CDT git cvsimport -p"-x" -C module-1 module &&
git cvsimport -p"-x" -C module-1 module &&
test_cmp actual-1 expect-1
'
-test_expect_success 'check timestamps with author-specific timezones' '
+test_expect_success PERL 'check timestamps with author-specific timezones' '
cat >cvs-authors <<-EOF &&
user1=User One <user1@domain.org>
LF='
'
-export _x05 _x40 _z40 LF
+# UTF-8 ZERO WIDTH NON-JOINER, which HFS+ ignores
+# when case-folding filenames
+u200c=$(printf '\342\200\214')
+
+export _x05 _x40 _z40 LF u200c
# Each test should start with something like this, after copyright notices:
#
#include "string-list.h"
#include "run-command.h"
#include "string-list.h"
+#include "commit.h"
#include "trailer.h"
/*
* Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
return only_spaces ? count : 0;
}
+/* Get the index of the end of the trailers */
+static int find_trailer_end(struct strbuf **lines, int patch_start)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int i, ignore_bytes;
+
+ for (i = 0; i < patch_start; i++)
+ strbuf_addbuf(&sb, lines[i]);
+ ignore_bytes = ignore_non_trailer(&sb);
+ strbuf_release(&sb);
+ for (i = patch_start - 1; i >= 0 && ignore_bytes > 0; i--)
+ ignore_bytes -= lines[i]->len;
+
+ return i + 1;
+}
+
static int has_blank_line_before(struct strbuf **lines, int start)
{
for (;start >= 0; start--) {
struct trailer_item **in_tok_last)
{
int count = 0;
- int patch_start, trailer_start, i;
+ int patch_start, trailer_start, trailer_end, i;
/* Get the line count */
while (lines[count])
count++;
patch_start = find_patch_start(lines, count);
- trailer_start = find_trailer_start(lines, patch_start);
+ trailer_end = find_trailer_end(lines, patch_start);
+ trailer_start = find_trailer_start(lines, trailer_end);
/* Print lines before the trailers as is */
print_lines(lines, 0, trailer_start);
printf("\n");
/* Parse trailer lines */
- for (i = trailer_start; i < patch_start; i++) {
+ for (i = trailer_start; i < trailer_end; i++) {
if (lines[i]->buf[0] != comment_line_char) {
struct trailer_item *new = create_trailer_item(lines[i]->buf);
add_trailer_item(in_tok_first, in_tok_last, new);
}
}
- return patch_start;
+ return trailer_end;
}
static void free_all(struct trailer_item **first)
struct trailer_item *in_tok_last = NULL;
struct trailer_item *arg_tok_first;
struct strbuf **lines;
- int patch_start;
+ int trailer_end;
/* Default config must be setup first */
git_config(git_trailer_default_config, NULL);
lines = read_input_file(file);
/* Print the lines before the trailers */
- patch_start = process_input_file(lines, &in_tok_first, &in_tok_last);
+ trailer_end = process_input_file(lines, &in_tok_first, &in_tok_last);
arg_tok_first = process_command_line_args(trailers);
free_all(&in_tok_first);
/* Print the lines after the trailers as is */
- print_lines(lines, patch_start, INT_MAX);
+ print_lines(lines, trailer_end, INT_MAX);
strbuf_list_free(lines);
}
return add_cache_entry(ce, opt);
}
-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
+static int read_one_entry(const unsigned char *sha1, struct strbuf *base,
+ const char *pathname, unsigned mode, int stage,
+ void *context)
{
- return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+ return read_one_entry_opt(sha1, base->buf, base->len, pathname,
+ mode, stage,
ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
}
* This is used when the caller knows there is no existing entries at
* the stage that will conflict with the entry being added.
*/
-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
+static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,
+ const char *pathname, unsigned mode, int stage,
+ void *context)
{
- return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+ return read_one_entry_opt(sha1, base->buf, base->len, pathname,
+ mode, stage,
ADD_CACHE_JUST_APPEND);
}
continue;
}
- switch (fn(entry.sha1, base->buf, base->len,
+ switch (fn(entry.sha1, base,
entry.path, entry.mode, stage, context)) {
case 0:
continue;
#include "object.h"
extern const char *tree_type;
+struct strbuf;
struct tree {
struct object object;
struct tree *parse_tree_indirect(const unsigned char *sha1);
#define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
+typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *);
extern int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
opts->unpack_rejects[i].strdup_strings = 1;
}
-static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
{
clear |= CE_HASHED;
set |= CE_WT_REMOVE;
ce->ce_flags = (ce->ce_flags & ~clear) | set;
- add_index_entry(&o->result, ce,
- ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+ return add_index_entry(&o->result, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
static struct cache_entry *dup_entry(const struct cache_entry *ce)
for (i = 0; i < n; i++)
if (src[i] && src[i] != o->df_conflict_entry)
- do_add_entry(o, src[i], 0, 0);
+ if (do_add_entry(o, src[i], 0, 0))
+ return -1;
+
return 0;
}
if (o->dst_index) {
discard_index(o->dst_index);
*o->dst_index = o->result;
+ } else {
+ discard_index(&o->result);
}
done:
return chrlen;
}
+
+/*
+ * Pick the next char from the stream, folding as an HFS+ filename comparison
+ * would. Note that this is _not_ complete by any means. It's just enough
+ * to make is_hfs_dotgit() work, and should not be used otherwise.
+ */
+static ucs_char_t next_hfs_char(const char **in)
+{
+ while (1) {
+ ucs_char_t out = pick_one_utf8_char(in, NULL);
+ /*
+ * check for malformed utf8. Technically this
+ * gets converted to a percent-sequence, but
+ * returning 0 is good enough for is_hfs_dotgit
+ * to realize it cannot be .git
+ */
+ if (!*in)
+ return 0;
+
+ /* these code points are ignored completely */
+ switch (out) {
+ case 0x200c: /* ZERO WIDTH NON-JOINER */
+ case 0x200d: /* ZERO WIDTH JOINER */
+ case 0x200e: /* LEFT-TO-RIGHT MARK */
+ case 0x200f: /* RIGHT-TO-LEFT MARK */
+ case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */
+ case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */
+ case 0x202c: /* POP DIRECTIONAL FORMATTING */
+ case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */
+ case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */
+ case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */
+ case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */
+ case 0x206c: /* INHIBIT ARABIC FORM SHAPING */
+ case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */
+ case 0x206e: /* NATIONAL DIGIT SHAPES */
+ case 0x206f: /* NOMINAL DIGIT SHAPES */
+ case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */
+ continue;
+ }
+
+ /*
+ * there's a great deal of other case-folding that occurs,
+ * but this is enough to catch anything that will convert
+ * to ".git"
+ */
+ return tolower(out);
+ }
+}
+
+int is_hfs_dotgit(const char *path)
+{
+ ucs_char_t c;
+
+ if (next_hfs_char(&path) != '.' ||
+ next_hfs_char(&path) != 'g' ||
+ next_hfs_char(&path) != 'i' ||
+ next_hfs_char(&path) != 't')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c && !is_dir_sep(c))
+ return 0;
+
+ return 1;
+}
int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
+/*
+ * Returns true if the the path would match ".git" after HFS case-folding.
+ * The path should be NUL-terminated, but we will match variants of both ".git\0"
+ * and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
+ * and verify_path().
+ */
+int is_hfs_dotgit(const char *path);
+
#endif
static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
{
struct child_process sm_summary = CHILD_PROCESS_INIT;
- struct argv_array argv = ARGV_ARRAY_INIT;
struct strbuf cmd_stdout = STRBUF_INIT;
struct strbuf summary = STRBUF_INIT;
char *summary_content;
argv_array_pushf(&sm_summary.env_array, "GIT_INDEX_FILE=%s",
s->index_file);
- argv_array_push(&argv, "submodule");
- argv_array_push(&argv, "summary");
- argv_array_push(&argv, uncommitted ? "--files" : "--cached");
- argv_array_push(&argv, "--for-status");
- argv_array_push(&argv, "--summary-limit");
- argv_array_pushf(&argv, "%d", s->submodule_summary);
+ argv_array_push(&sm_summary.args, "submodule");
+ argv_array_push(&sm_summary.args, "summary");
+ argv_array_push(&sm_summary.args, uncommitted ? "--files" : "--cached");
+ argv_array_push(&sm_summary.args, "--for-status");
+ argv_array_push(&sm_summary.args, "--summary-limit");
+ argv_array_pushf(&sm_summary.args, "%d", s->submodule_summary);
if (!uncommitted)
- argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
+ argv_array_push(&sm_summary.args, s->amend ? "HEAD^" : "HEAD");
- sm_summary.argv = argv.argv;
sm_summary.git_cmd = 1;
sm_summary.no_stdin = 1;
fflush(s->fp);
sm_summary.out = -1;
run_command(&sm_summary);
- argv_array_clear(&argv);
len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);