--- /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.2.2 Release Notes
+========================
+
+Fixes since v2.2.1
+------------------
+
+ * "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.
+
+ * "git config --get-color" did not parse its command line arguments
+ carefully.
+
+ * open() emulated on Windows platforms did not give EISDIR upon
+ an attempt to open a directory for writing.
+
+ * A few code paths used abs() when they should have used labs() on
+ long integers.
+
+ * "gitweb" used to depend on a behaviour recent CGI.pm deprecated.
+
+ * "git init" (hence "git clone") initialized the per-repository
+ configuration file .git/config with x-bit by mistake.
+
+ * Git 2.0 was supposed to make the "simple" mode for the default of
+ "git push", but it didn't.
+
+ * "Everyday" document had a broken link.
+
+ * The build procedure did not bother fixing perl and python scripts
+ when NO_PERL and NO_PYTHON build-time configuration changed.
+
+ * The code that reads the reflog from the newer to the older entries
+ did not handle an entry that crosses a boundary of block it uses to
+ read them correctly.
+
+ * "git apply" was described in the documentation to take --ignore-date
+ option, which it does not.
+
+ * Traditionally we tried to avoid interpreting date strings given by
+ the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when
+ used early November 2014 was taken as "October 12, 2014" because it
+ is likely that a date in the future, December 10, is a mistake.
+ This heuristics has been loosened to allow people to express future
+ dates (most notably, --until=<date> may want to be far in the
+ future) and we no longer tiebreak by future-ness of the date when
+
+ (1) ISO-like format is used, and
+ (2) the string can make sense interpreted as both y-m-d and y-d-m.
+
+ Git may still have to use the heuristics to tiebreak between dd/mm/yy
+ and mm/dd/yy, though.
+
+ * The code to abbreviate an object name to its short unique prefix
+ has been optimized when no abbreviation was requested.
+
+ * "git add --ignore-errors ..." did not ignore an error to
+ give a file that did not exist.
+
+ * Git did not correctly read an overlong refname from a packed refs
+ file.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
Ports
- *
+ * Recent gcc toolchain on Cygwin started throwing compilation warning,
+ which has been squelched.
+
UI, Workflows & Features
note from the object but with --allow-empty we will store a
(surprise!) note that is empty.
+ * "git interpret-trailers" learned to properly handle the
+ "Conflicts:" block at the end.
+
+ * "git am" learned "--message-id" option to copy the message ID of
+ the incoming e-mail to the log message of resulting commit.
+
+ * "git clone --reference=<over there>" learned the "--dissociate"
+ option to go with it; it borrows objects from the reference object
+ store while cloning only to reduce network traffic and then
+ dissociates the resulting clone from the reference by performing
+ local copies of borrowed objects.
+
+ * "git send-email" learned "--transfer-encoding" option to force a
+ non-fault Content-Transfer-Encoding header (e.g. base64).
+
+ * "git send-email" normally identifies itself via X-Mailer: header in
+ the message it sends out. A new command line flag --no-xmailer
+ allows the user to squelch the header.
+
+ * "git push" into a repository with a working tree normally refuses
+ to modify the branch that is checked out. The command learned to
+ optionally do an equivalent of "git reset --hard" only when there
+ is no change to the working tree and the index instead, which would
+ be useful to "deploy" by pushing into a repository.
+
+ * "git new-workdir" (in contrib/) can be used to populate an empty
+ and existing directory now.
+
+ * Credential helpers are asked in turn until one of them give
+ positive response, which is cumbersome to turn off when you need to
+ run Git in an automated setting. The credential helper interface
+ learned to allow a helper to say "stop, don't ask other helpers."
+ Also GIT_TERMINAL_PROMPT environment can be set to false to disable
+ our built-in prompt mechanism for passwords.
+
+ * "git branch -d" (delete) and "git branch -m" (move) learned to
+ honor "-f" (force) flag; unlike many other subcommands, the way to
+ force these have been with separate "-D/-M" options, which was
+ inconsistent.
+
+ * "diff-highlight" filter (in contrib/) allows its color output to be
+ customized via configuration variables.
+
+ * "git imap-send" learned to take "-v" (verbose) and "-q" (quiet)
+ command line options.
+
+ * "git imap-send" now can be built to use cURL library to talk to
+ IMAP servers (if the library is recent enough, of course).
+ This allows you to use authenticate method other than CRAM-MD5,
+ among other things.
+
Performance, Internal Implementation, Development Support etc.
- *
+ * Earlier we made "rev-list --object-edge" more aggressively list the
+ objects at the edge commits, in order to reduce number of objects
+ fetched into a shallow repository, but the change affected cases
+ other than "fetching into a shallow repository" and made it
+ unusably slow (e.g. fetching into a normal repository should not
+ have to suffer the overhead from extra processing). Limit it to a
+ more specific case by introducing --objects-edge-aggressive, a new
+ option to rev-list.
+
+ * Squelched useless compiler warnings on Mac OS X regarding the
+ crypto API.
+
+ * The procedure to generate unicode table has been simplified.
+
+ * Some filesystems assign filemodes in a strange way, fooling then
+ automatic "filemode trustability" check done during a new
+ repository creation. The initialization codepath has been hardened
+ against this issue.
+
+ * The codepath in "git remote update --prune" to drop many refs has
+ been optimized.
+
+ * The API into get_merge_bases*() family of functions was easy to
+ misuse, which has been corrected to make it harder to do so.
+
+ * Long overdue departure from the assumption that S_IFMT is shared by
+ everybody made in 2005, which was necessary to port to z/OS.
+
+ * "git push" and "git fetch" did not communicate an overlong refname
+ correctly. Now it uses 64kB sideband to accommodate longer ones.
+
+ * Recent GPG changes the keyring format and drops support for RFC1991
+ formatted signatures, breaking our existing tests.
+
+ * "git-prompt" (in contrib/) used a variable from the global scope,
+ possibly contaminating end-user's namespace.
Also contains various documentation updates and code clean-ups.
track are contained in this release (see the maintenance releases'
notes for details).
+ * The logic in "git bisect bad HEAD" etc. to avoid forcing the test
+ of the common ancestor of bad and good commits was broken.
+ (merge 07913d5 cc/bisect-rev-parsing later to maint).
+
+ * "git checkout-index --temp=$target $path" did not work correctly
+ for paths outside the current subdirectory in the project.
+ (merge 74c4de5 es/checkout-index-temp later to maint).
+
+ * The report from "git checkout" on a branch that builds on another
+ local branch by setting its branch.*.merge to branch name (not a
+ full refname) incorrectly said that the upstream is gone.
+ (merge 05e7368 jc/checkout-local-track-report later to maint).
+
+ * With The git-prompt support (in contrib/), using the exit status of
+ the last command in the prompt, e.g. PS1='$(__git_ps1) $? ', did
+ not work well, because the helper function stomped on the exit
+ status.
+ (merge eb443e3 tf/prompt-preserve-exit-status later to maint).
+
+
+ * Recent update to "git commit" broke amending an existing commit
+ with bogus author/committer lines without a valid e-mail address.
+ (merge c83a509 jk/commit-date-approxidate later to maint).
+
+ * The lockfile API used to get confused which file to clean up when
+ the process moved the $cwd after creating a lockfile.
+ (merge fa137f6 nd/lockfile-absolute later to maint).
+
+ * Traditionally we tried to avoid interpreting date strings given by
+ the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when
+ used early November 2014 was taken as "October 12, 2014" because it
+ is likely that a date in the future, December 10, is a mistake.
+ This heuristics has been loosened to allow people to express future
+ dates (most notably, --until=<date> may want to be far in the
+ future) and we no longer tiebreak by future-ness of the date when
+
+ (1) ISO-like format is used, and
+ (2) the string can make sense interpreted as both y-m-d and y-d-m.
+
+ Git may still have to use the heuristics to tiebreak between dd/mm/yy
+ and mm/dd/yy, though.
+ (merge d372395 jk/approxidate-avoid-y-d-m-over-future-dates later to maint).
+
+ * Git did not correctly read an overlong refname from a packed refs
+ file.
+ (merge ea41783 jk/read-packed-refs-without-path-max later to maint).
+
+ * "git apply" was described in the documentation to take --ignore-date
+ option, which it does not.
+ (merge 0cef4e7 rw/apply-does-not-take-ignore-date later to maint).
+
+ * "git add -i" did not notice when the interactive command input
+ stream went away and kept asking the same question.
+ (merge a8bec7a jk/add-i-read-error later to maint).
+
+ * "git send-email" did not handle RFC 2047 encoded headers quite
+ right.
+ (merge ab47e2a rd/send-email-2047-fix later to maint).
+
+ * New tag object format validation added in 2.2 showed garbage after
+ a tagname it reported in its error message.
+ (merge a1e920a js/fsck-tag-validation later to maint).
+
+ * The code that reads the reflog from the newer to the older entries
+ did not handle an entry that crosses a boundary of block it uses to
+ read them correctly.
+ (merge 69216bf jk/for-each-reflog-ent-reverse later to maint).
+
+ * "git diff -B -M" after making a new copy B out of an existing file
+ A and then editing A extensively ought to report that B was created
+ by copying A and A was modified, which is what "git diff -C"
+ reports, but it instead said A was renamed to B and A was edited
+ heavily in place. This was not just incoherent but also failed to
+ apply with "git apply". The report has been corrected to match what
+ "git diff -C" produces for this case.
+ (merge 6936b58 jc/diff-b-m later to maint).
+
+ * In files we pre-populate for the user to edit with commented hints,
+ a line of hint that is indented with a tab used to show as '#' (or
+ any comment char), ' ' (space), and then the hint text that began
+ with the tab, which some editors flag as an indentation error (tab
+ following space). We now omit the space after the comment char in
+ such a case.
+ (merge d55aeb7 jc/strbuf-add-lines-avoid-sp-ht-sequence later to maint).
+
+ * "git ls-tree" does not support path selection based on negative
+ pathspecs, but did not error out when negative pathspecs are given.
+ (merge f1f6224 nd/ls-tree-pathspec later to maint).
+
+ * The function sometimes returned a non-freeable memory and some
+ other times returned a piece of memory that must be freed, leading
+ to inevitable leaks.
+ (merge 59362e5 jc/exec-cmd-system-path-leak-fix later to maint).
+
+ * The code to abbreviate an object name to its short unique prefix
+ has been optimized when no abbreviation was requested.
+ (merge 61e704e mh/find-uniq-abbrev later to maint).
+
+ * "git add --ignore-errors ..." did not ignore an error to
+ give a file that did not exist.
+ (merge 1d31e5a mg/add-ignore-errors later to maint).
+
* "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.
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
You often want to add additional explanation about the patch,
other than the commit message itself. Place such "cover letter"
-material between the three dash lines and the diffstat. Git-notes
-can also be inserted using the `--notes` option.
+material between the three-dash line and the diffstat. For
+patches requiring multiple iterations of review and discussion,
+an explanation of changes between each iteration can be kept in
+Git-notes and inserted automatically following the three-dash
+line via `git format-patch --notes`.
Do not attach the patch as a MIME attachment, compressed or not.
Do not let your e-mail client send quoted-printable. Do not let
person who certified (a), (b) or (c) and I have not modified
it.
- (d) I understand and agree that this project and the contribution
- are public and that a record of the contribution (including all
- personal information I submit with it, including my sign-off) is
- maintained indefinitely and may be redistributed consistent with
- this project or the open source license(s) involved.
+ (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
then you just add a line saying
- Signed-off-by: Random J Developer <random@developer.example.org>
+ Signed-off-by: Random J Developer <random@developer.example.org>
This line can be automatically added by Git if you run the git-commit
command with the -s option.
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
`magenta`, `cyan` and `white`; the attributes are `bold`, `dim`, `ul`,
`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.
+doesn't matter. Attributes may be turned off specifically by prefixing
+them with `no` (e.g., `noreverse`, `noul`, etc).
+
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).
+terminals may support this). If your terminal supports it, you may also
+specify 24-bit RGB values as hex, like `#ff0ab3`.
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::
+sendemail.xmailer::
See linkgit:git-send-email[1] for description.
sendemail.signedoffcc::
SYNOPSIS
--------
[verse]
-'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
+'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing]
[--] [<pathspec>...]
--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.
it is supposed to apply to and we have those blobs
available locally.
---ignore-date::
--ignore-space-change::
--ignore-whitespace::
--whitespace=<option>::
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::
'git clone' [--template=<template_directory>]
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
- [--separate-git-dir <git dir>]
+ [--dissociate] [--separate-git-dir <git dir>]
[--depth <depth>] [--[no-]single-branch]
[--recursive | --recurse-submodules] [--] <repository>
[<directory>]
require fewer objects to be copied from the repository
being cloned, reducing network and local storage costs.
+
-*NOTE*: see the NOTE for the `--shared` option.
+*NOTE*: see the NOTE for the `--shared` option, and also the
+`--dissociate` option.
+
+--dissociate::
+ Borrow the objects from reference repositories specified
+ with the `--reference` options only to reduce network
+ transfer and stop borrowing from them after a clone is made
+ by making necessary local copies of borrowed objects.
--quiet::
-q::
SYNOPSIS
--------
[verse]
-'git imap-send'
+'git imap-send' [-v] [-q] [--[no-]curl]
DESCRIPTION
git format-patch --signoff --stdout --attach origin | git imap-send
+OPTIONS
+-------
+
+-v::
+--verbose::
+ Be verbose.
+
+-q::
+--quiet::
+ Be quiet.
+
+--curl::
+ Use libcurl to communicate with the IMAP server, unless tunneling
+ into it. Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
+ option set.
+
+--no-curl::
+ Talk to the IMAP server using git's own IMAP routines instead of
+ using libcurl.
+
+
CONFIGURATION
-------------
imap.authMethod::
Specify authenticate method for authentication with IMAP server.
- Current supported method is 'CRAM-MD5' only. If this is not set
+ If Git was built with the NO_CURL option, or if your curl version is older
+ than 7.34.0, or if you're running git-imap-send with the `--no-curl`
+ option, the only supported method is 'CRAM-MD5'. If this is not set
then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
Examples
-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
[--no-reuse-delta] [--delta-base-offset] [--non-empty]
[--local] [--incremental] [--window=<n>] [--depth=<n>]
[--revs [--unpacked | --all]] [--stdout | base-name]
- [--keep-true-parents] < object-list
+ [--shallow] [--keep-true-parents] < object-list
DESCRIPTION
self-contained. Use `git index-pack --fix-thin`
(see linkgit:git-index-pack[1]) to restore the self-contained property.
+--shallow::
+ Optimize a pack that will be provided to a client with a shallow
+ repository. This option, combined with \--thin, can result in a
+ smaller pack at the cost of speed.
+
--delta-base-offset::
A packed archive can express the base object of a delta as
either a 20-byte object name or as an offset in the
[ \--extended-regexp | -E ]
[ \--fixed-strings | -F ]
[ \--date=(local|relative|default|iso|iso-strict|rfc|short) ]
- [ [\--objects | \--objects-edge] [ \--unpacked ] ]
+ [ [ \--objects | \--objects-edge | \--objects-edge-aggressive ]
+ [ \--unpacked ] ]
[ \--pretty | \--header ]
[ \--bisect ]
[ \--bisect-vars ]
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.
+
+--xmailer::
+--no-xmailer::
+ Add (or prevent adding) the "X-Mailer:" header. By default,
+ the header is added, but it can be turned off by setting the
+ `sendemail.xmailer` configuration variable to `false`.
Sending
~~~~~~~
Legacy alias for '--smtp-encryption ssl'.
--smtp-ssl-cert-path::
- Path to ca-certificates (either a directory or a single file).
- Set it to an empty string to disable certificate verification.
- Defaults to the value set to the 'sendemail.smtpsslcertpath'
- configuration variable, if set, or `/etc/ssl/certs` otherwise.
+ Path to a store of trusted CA certificates for SMTP SSL/TLS
+ certificate validation (either a directory that has been processed
+ by 'c_rehash', or a single file containing one or more PEM format
+ certificates concatenated together: see verify(1) -CAfile and
+ -CApath for more information on these). Set it to an empty string
+ to disable certificate verification. Defaults to the value of the
+ 'sendemail.smtpsslcertpath' configuration variable, if set, or the
+ backing SSL library's compiled-in default otherwise (which should
+ be the best choice on most platforms).
--smtp-user=<user>::
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
--------
[verse]
'git stripspace' [-s | --strip-comments] < input
+'git stripspace' [-c | --comment-lines] < input
DESCRIPTION
-----------
Set the execute permissions on the updated files.
--[no-]assume-unchanged::
- When these flags are specified, the object names recorded
- for the paths are not updated. Instead, these options
- set and unset the "assume unchanged" bit for the
- paths. When the "assume unchanged" bit is on, Git stops
- checking the working tree files for possible
- modifications, so you need to manually unset the bit to
- tell Git when you change the working tree file. This is
+ When this flag is specified, the object names recorded
+ for the paths are not updated. Instead, this option
+ sets/unsets the "assume unchanged" bit for the
+ paths. When the "assume unchanged" bit is on, the user
+ promises not to change the file and allows Git to assume
+ that the working tree file matches what is recorded in
+ the index. If you want to change the working tree file,
+ you need to unset the bit to tell Git. This is
sometimes helpful when working with a big project on a
filesystem that has very slow lstat(2) system call
(e.g. cifs).
+
-This option can be also used as a coarse file-level mechanism
-to ignore uncommitted changes in tracked files (akin to what
-`.gitignore` does for untracked files).
Git will fail (gracefully) in case it needs to modify this file
in the index e.g. when merging in a commit;
thus, in case the assumed-untracked file is changed upstream,
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.2/git.html[documentation for release 2.2.2]
* release notes for
+ link:RelNotes/2.2.2.txt[2.2.2],
+ 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 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
The purpose of gitignore files is to ensure that certain files
not tracked by Git remain untracked.
-To ignore uncommitted changes in a file that is already tracked,
-use 'git update-index {litdd}assume-unchanged'.
-
To stop tracking a file that is currently tracked, use
'git rm --cached'.
SEE ALSO
--------
linkgit:git-rm[1],
-linkgit:git-update-index[1],
linkgit:gitrepository-layout[5],
linkgit:git-check-ignore[1]
--objects-edge::
Similar to `--objects`, but also print the IDs of excluded
commits prefixed with a ``-'' character. This is used by
- linkgit:git-pack-objects[1] to build ``thin'' pack, which records
+ linkgit:git-pack-objects[1] to build a ``thin'' pack, which records
objects in deltified form based on objects contained in these
excluded commits to reduce network traffic.
+--objects-edge-aggressive::
+ Similar to `--objects-edge`, but it tries harder to find excluded
+ commits at the cost of increased time. This is used instead of
+ `--objects-edge` to build ``thin'' packs for shallow repositories.
+
--unpacked::
Only useful with `--objects`; print the object IDs that are not
in packs.
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.
in a separate file. This extension records the changes to be made on
top of that to produce the final index.
- The signature for this extension is { 'l', 'i, 'n', 'k' }.
+ The signature for this extension is { 'l', 'i', 'n', 'k' }.
The extension consists of:
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.2.0.GIT
+DEF_VER=v2.3.0-rc0
LF='
'
so you might need to install additional packages other than Perl
itself, e.g. Time::HiRes.
- - "openssl" library is used by git-imap-send to use IMAP over SSL.
- If you don't need it, use NO_OPENSSL.
+ - git-imap-send needs the OpenSSL library to talk IMAP over SSL if
+ you are using libcurl older than 7.34.0. Otherwise you can use
+ NO_OPENSSL without losing git-imap-send.
By default, git uses OpenSSL for SHA1 but it will use its own
library (inspired by Mozilla's) with either NO_OPENSSL or
BLK_SHA1. Also included is a version optimized for PowerPC
(PPC_SHA1).
- - "libcurl" library is used by git-http-fetch and git-fetch. You
- might also want the "curl" executable for debugging purposes.
- If you do not use http:// or https:// repositories, you do not
- have to have them (use NO_CURL).
+ - "libcurl" library is used by git-http-fetch, git-fetch, and, if
+ the curl version >= 7.34.0, for git-imap-send. You might also
+ want the "curl" executable for debugging purposes. If you do not
+ use http:// or https:// repositories, and do not want to put
+ patches into an IMAP mailbox, you do not have to have them
+ (use NO_CURL).
- "expat" library; git-http-push uses it for remote lock
management over DAV. Similar to "curl" above, this is optional
# 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.
# return NULL when it receives a bogus time_t.
#
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
+#
+# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC in librt.
+#
+# Define NO_HMAC_CTX_CLEANUP if your OpenSSL is version 0.9.6b or earlier to
+# cleanup the HMAC context with the older HMAC_cleanup function.
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
BASIC_CFLAGS += -DHAVE_ALLOCA_H
endif
+IMAP_SEND_BUILDDEPS =
+IMAP_SEND_LDFLAGS = $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+
ifdef NO_CURL
BASIC_CFLAGS += -DNO_CURL
REMOTE_CURL_PRIMARY =
PROGRAM_OBJS += http-push.o
endif
endif
+ curl_check := $(shell (echo 072200; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+ ifeq "$(curl_check)" "072200"
+ USE_CURL_FOR_IMAP_SEND = YesPlease
+ endif
+ ifdef USE_CURL_FOR_IMAP_SEND
+ BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
+ IMAP_SEND_BUILDDEPS = http.o
+ IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
+ endif
ifndef NO_EXPAT
ifdef EXPATDIR
BASIC_CFLAGS += -I$(EXPATDIR)/include
ifdef NEEDS_CRYPTO_WITH_SSL
OPENSSL_LIBSSL += -lcrypto
endif
+ ifdef NO_HMAC_CTX_CLEANUP
+ BASIC_CFLAGS += -DNO_HMAC_CTX_CLEANUP
+ endif
else
BASIC_CFLAGS += -DNO_OPENSSL
BLK_SHA1 = 1
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
EXTLIBS += -lrt
endif
+ifdef HAVE_CLOCK_MONOTONIC
+ BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK = NoThanks
endif
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
-DGIT_LOCALE_PATH='"$(localedir_SQ)"'
-http-push.sp http.sp http-walker.sp remote-curl.sp: SPARSE_FLAGS += \
+http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SPARSE_FLAGS += \
-DCURL_DISABLE_TYPECHECK
ifdef NO_EXPAT
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
-git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+ $(LIBS) $(IMAP_SEND_LDFLAGS)
git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
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;
int rev_nr;
struct commit **rev = get_bad_and_good_commits(&rev_nr);
- result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+ result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);
for (; result; result = result->next) {
const unsigned char *mb = result->item->object.sha1;
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 (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);
int cmd_branch(int argc, const char **argv, const char *prefix)
{
- int delete = 0, rename = 0, force_create = 0, list = 0;
+ int delete = 0, rename = 0, force = 0, list = 0;
int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0, edit_description = 0;
int quiet = 0, unset_upstream = 0;
OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOL(0, "edit-description", &edit_description,
N_("edit the description for the branch")),
- OPT__FORCE(&force_create, N_("force creation (when already exists)")),
+ OPT__FORCE(&force, N_("force creation, move/rename, deletion")),
{
OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
N_("commit"), N_("print only not merged branches"),
if (with_commit || merge_filter != NO_FILTER)
list = 1;
- if (!!delete + !!rename + !!force_create + !!new_upstream +
+ if (!!delete + !!rename + !!new_upstream +
list + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
colopts = 0;
}
+ if (force) {
+ delete *= 2;
+ rename *= 2;
+ }
+
if (delete) {
if (!argc)
die(_("branch name required"));
branch_existed = ref_exists(branch->refname);
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
- force_create, reflog, 0, quiet, track);
+ force, reflog, 0, quiet, track);
/*
* We only show the instructions if the user gave us
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
-#include "exec_cmd.h"
-#include "tag.h"
-#include "tree.h"
#include "builtin.h"
#include "parse-options.h"
-#include "diff.h"
#include "userdiff.h"
#include "streaming.h"
static struct checkout state;
-static void write_tempfile_record(const char *name, int prefix_length)
+static void write_tempfile_record(const char *name, const char *prefix)
{
int i;
fputs(topath[checkout_stage], stdout);
putchar('\t');
- write_name_quoted(name + prefix_length, stdout, line_termination);
+ write_name_quoted_relative(name, prefix, stdout, line_termination);
for (i = 0; i < 4; i++) {
topath[i][0] = 0;
}
}
-static int checkout_file(const char *name, int prefix_length)
+static int checkout_file(const char *name, const char *prefix)
{
int namelen = strlen(name);
int pos = cache_name_pos(name, namelen);
if (did_checkout) {
if (to_tempfile)
- write_tempfile_record(name, prefix_length);
+ write_tempfile_record(name, prefix);
return errs > 0 ? -1 : 0;
}
if (last_ce && to_tempfile) {
if (ce_namelen(last_ce) != ce_namelen(ce)
|| memcmp(last_ce->name, ce->name, ce_namelen(ce)))
- write_tempfile_record(last_ce->name, prefix_length);
+ write_tempfile_record(last_ce->name, prefix);
}
if (checkout_entry(ce, &state,
to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
last_ce = ce;
}
if (last_ce && to_tempfile)
- write_tempfile_record(last_ce->name, prefix_length);
+ write_tempfile_record(last_ce->name, prefix);
if (errs)
/* we have already done our error reporting.
* exit with the same code as die().
if (read_from_stdin)
die("git checkout-index: don't mix '--stdin' and explicit filenames");
p = prefix_path(prefix, prefix_length, arg);
- checkout_file(p, prefix_length);
+ checkout_file(p, prefix);
if (p < arg || p > arg + strlen(arg))
free((char *)p);
}
strbuf_swap(&buf, &nbuf);
}
p = prefix_path(prefix, prefix_length, buf.buf);
- checkout_file(p, prefix_length);
+ checkout_file(p, prefix);
if (p < buf.buf || p > buf.buf + buf.len)
free((char *)p);
}
}
-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;
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);
switch (stuff->type) {
default:
- die("Bad type of menu_staff when print menu");
+ die("Bad type of menu_stuff when print menu");
case MENU_STUFF_TYPE_MENU_ITEM:
menu_item = (struct menu_item *)stuff->stuff;
for (i = 0; i < stuff->nr; i++, menu_item++) {
static int option_progress = -1;
static struct string_list option_config;
static struct string_list option_reference;
+static int option_dissociate;
static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
{
N_("create a shallow clone of that depth")),
OPT_BOOL(0, "single-branch", &option_single_branch,
N_("clone only one branch, HEAD or --branch")),
+ OPT_BOOL(0, "dissociate", &option_dissociate,
+ N_("use --reference only while cloning")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
strbuf_release(&value);
}
+static void dissociate_from_references(void)
+{
+ static const char* argv[] = { "repack", "-a", "-d", NULL };
+
+ if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
+ die(_("cannot repack to clean up"));
+ if (unlink(git_path("objects/info/alternates")) && errno != ENOENT)
+ die_errno(_("cannot unlink temporary alternates file"));
+}
+
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
if (option_reference.nr)
setup_reference();
+ else if (option_dissociate) {
+ warning(_("--dissociate given, but there is no --reference"));
+ option_dissociate = 0;
+ }
fetch_pattern = value.buf;
refspec = parse_fetch_refspec(1, &fetch_pattern);
transport_unlock_pack(transport);
transport_disconnect(transport);
+ if (option_dissociate)
+ dissociate_from_references();
+
junk_mode = JUNK_LEAVE_REPO;
err = checkout();
continue;
}
- if (!memcmp(arg, "-S", 2)) {
- sign_commit = arg + 2;
+ if (skip_prefix(arg, "-S", &sign_commit))
continue;
- }
if (!strcmp(arg, "--no-gpg-sign")) {
sign_commit = NULL;
return !!(current_head->parents && current_head->parents->next);
}
+static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
+{
+ if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
+ die("BUG: unable to parse our own ident: %s", buf->buf);
+}
+
static void export_one(const char *var, const char *s, const char *e, int hack)
{
struct strbuf buf = STRBUF_INIT;
strbuf_release(&buf);
}
-static int sane_ident_split(struct ident_split *person)
-{
- if (!person->name_begin || !person->name_end ||
- person->name_begin == person->name_end)
- return 0; /* no human readable name */
- if (!person->mail_begin || !person->mail_end ||
- person->mail_begin == person->mail_end)
- return 0; /* no usable mail */
- if (!person->date_begin || !person->date_end ||
- !person->tz_begin || !person->tz_end)
- return 0;
- return 1;
-}
-
static int parse_force_date(const char *in, struct strbuf *out)
{
strbuf_addch(out, '@');
}
strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
- if (!split_ident_line(&author, author_ident->buf, author_ident->len) &&
- sane_ident_split(&author)) {
- export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
- export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
- export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
- }
-
+ assert_split_ident(&author, author_ident);
+ export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
+ export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
+ export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
free(name);
free(email);
free(date);
}
-static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
-{
- if (split_ident_line(id, buf->buf, buf->len) ||
- !sane_ident_split(id))
- die(_("Malformed ident string: '%s'"), buf->buf);
-}
-
static int author_date_is_interesting(void)
{
return author_message || force_date;
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"));
status_printf_ln(s, GIT_COLOR_NORMAL,
"%s", only_include_assumed);
- split_ident_or_die(&ai, author_ident);
- split_ident_or_die(&ci, &committer_ident);
+ /*
+ * These should never fail because they come from our own
+ * fmt_ident. They may fail the sane_ident test, but we know
+ * that the name and mail pointers will at least be valid,
+ * which is enough for our tests and printing here.
+ */
+ assert_split_ident(&ai, author_ident);
+ assert_split_ident(&ci, &committer_ident);
if (ident_cmp(&ai, &ci))
status_printf_ln(s, GIT_COLOR_NORMAL,
strbuf_addf(out, " : %.*s", (int)(ep - bp), bp);
bp = ep;
}
- if (out->buf[out->len - 1] != '\n')
- strbuf_addch(out, '\n');
+ strbuf_complete_line(out);
}
strbuf_release(&desc);
}
starts_with(name, "upstream")) {
char buf[40];
- stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (stat_tracking_info(branch, &num_ours,
+ &num_theirs) != 1)
+ continue;
+
if (!num_ours && !num_theirs)
v->s = "";
else if (!num_ours) {
} else if (!strcmp(formatp, "trackshort") &&
starts_with(name, "upstream")) {
assert(branch);
- stat_tracking_info(branch, &num_ours, &num_theirs);
+
+ if (stat_tracking_info(branch, &num_ours,
+ &num_theirs) != 1)
+ continue;
+
if (!num_ours && !num_theirs)
v->s = "=";
else if (!num_ours)
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);
}
/*
if (type == OBJ_BLOB && size > big_file_threshold)
buf = fixed_buf;
else
- buf = xmalloc(size);
+ buf = xmallocz(size);
memset(&stream, 0, sizeof(stream));
git_inflate_init(&stream);
git_zstream stream;
int status;
- data = xmalloc(consume ? 64*1024 : obj->size);
+ data = xmallocz(consume ? 64*1024 : obj->size);
inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
memset(&stream, 0, sizeof(stream));
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)
!lstat(path, &st2) &&
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 const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
- N_("git log [<options>] [<revision range>] [[--] <path>...]\n")
- N_(" or: git show [options] <object>..."),
+ N_("git log [<options>] [<revision range>] [[--] <path>...]"),
+ N_("git show [options] <object>..."),
NULL
};
}
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"))
{
struct commit_list *result;
- result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+ result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
if (!result)
return 1;
for (i = 0; i < revs.nr; i++)
revs.commit[i]->object.flags &= ~TMP_MARK;
- bases = get_merge_bases_many(derived, revs.nr, revs.commit, 0);
+ bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
/*
* There should be one and only one merge base, when we found
#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);
+ strbuf_release(&msgbuf);
fclose(fp);
rerere(allow_rerere_auto);
printf(_("Automatic merge failed; "
if (!remoteheads)
; /* already up-to-date */
else if (!remoteheads->next)
- common = get_merge_bases(head_commit, remoteheads->item, 1);
+ common = get_merge_bases(head_commit, remoteheads->item);
else {
struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list);
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
- common_one = get_merge_bases(head_commit, j->item, 1);
+ common_one = get_merge_bases(head_commit, j->item);
if (hashcmp(common_one->item->object.sha1,
j->item->object.sha1)) {
up_to_date = 0;
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);
{
int use_internal_rev_list = 0;
int thin = 0;
+ int shallow = 0;
int all_progress_implied = 0;
struct argv_array rp = ARGV_ARRAY_INIT;
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
OPT_BOOL(0, "thin", &thin,
N_("create thin packs")),
+ OPT_BOOL(0, "shallow", &shallow,
+ N_("create packs suitable for shallow fetches")),
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
N_("ignore packs that have companion .keep file")),
OPT_INTEGER(0, "compression", &pack_compression_level,
argv_array_push(&rp, "pack-objects");
if (thin) {
use_internal_rev_list = 1;
- argv_array_push(&rp, "--objects-edge");
+ argv_array_push(&rp, shallow
+ ? "--objects-edge-aggressive"
+ : "--objects-edge");
} else
argv_array_push(&rp, "--objects");
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;
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)
url = argv[1];
remote = remote_get(name);
- if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||
+ if (remote && (remote->url_nr > 1 ||
+ (strcmp(name, remote->url[0]) &&
+ strcmp(url, remote->url[0])) ||
remote->fetch_refspec_nr))
die(_("remote %s already exists."), name);
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;
}
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);
struct commit *a, *b;
a = lookup_commit_reference(sha1);
b = lookup_commit_reference(end);
- exclude = get_merge_bases(a, b, 1);
+ exclude = get_merge_bases(a, b);
while (exclude) {
struct commit_list *n = exclude->next;
show_rev(REVERSED,
#include "parse-options.h"
static const char* show_branch_usage[] = {
- N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
+ N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order]\n"
+ " [--current] [--color[=<when>] | --no-color] [--sparse]\n"
+ " [--more=<n> | --list | --independent | --merge-base]\n"
+ " [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
static void *get_data(unsigned long size)
{
git_zstream stream;
- void *buf = xmalloc(size);
+ void *buf = xmallocz(size);
memset(&stream, 0, sizeof(stream));
char *refname;
unsigned char new_sha1[20];
unsigned char old_sha1[20];
- int have_old;
refname = parse_refname(input, &next);
if (!refname)
die("verify: missing <ref>");
if (parse_next_sha1(input, &next, old_sha1, "verify", refname,
- PARSE_SHA1_OLD)) {
- hashclr(new_sha1);
- have_old = 0;
- } else {
- hashcpy(new_sha1, old_sha1);
- have_old = 1;
- }
+ PARSE_SHA1_OLD))
+ hashclr(old_sha1);
+
+ hashcpy(new_sha1, old_sha1);
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
- update_flags, have_old, msg, &err))
+ update_flags, 1, msg, &err))
die("%s", err.buf);
update_flags = 0;
*
* 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
/* Ignore the RESET at the end when giving the size */
const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
-static int parse_color(const char *name, int len)
+/* An individual foreground or background color. */
+struct color {
+ enum {
+ COLOR_UNSPECIFIED = 0,
+ COLOR_NORMAL,
+ COLOR_ANSI, /* basic 0-7 ANSI colors */
+ COLOR_256,
+ COLOR_RGB
+ } type;
+ /* The numeric value for ANSI and 256-color modes */
+ unsigned char value;
+ /* 24-bit RGB color values */
+ unsigned char red, green, blue;
+};
+
+/*
+ * "word" is a buffer of length "len"; does it match the NUL-terminated
+ * "match" exactly?
+ */
+static int match_word(const char *word, int len, const char *match)
{
+ return !strncasecmp(word, match, len) && !match[len];
+}
+
+static int get_hex_color(const char *in, unsigned char *out)
+{
+ unsigned int val;
+ val = (hexval(in[0]) << 4) | hexval(in[1]);
+ if (val & ~0xff)
+ return -1;
+ *out = val;
+ return 0;
+}
+
+static int parse_color(struct color *out, const char *name, int len)
+{
+ /* Positions in array must match ANSI color codes */
static const char * const color_names[] = {
- "normal", "black", "red", "green", "yellow",
+ "black", "red", "green", "yellow",
"blue", "magenta", "cyan", "white"
};
char *end;
int i;
+ long val;
+
+ /* First try the special word "normal"... */
+ if (match_word(name, len, "normal")) {
+ out->type = COLOR_NORMAL;
+ return 0;
+ }
+
+ /* Try a 24-bit RGB value */
+ if (len == 7 && name[0] == '#') {
+ if (!get_hex_color(name + 1, &out->red) &&
+ !get_hex_color(name + 3, &out->green) &&
+ !get_hex_color(name + 5, &out->blue)) {
+ out->type = COLOR_RGB;
+ return 0;
+ }
+ }
+
+ /* Then pick from our human-readable color names... */
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
- const char *str = color_names[i];
- if (!strncasecmp(name, str, len) && !str[len])
- return i - 1;
+ if (match_word(name, len, color_names[i])) {
+ out->type = COLOR_ANSI;
+ out->value = i;
+ return 0;
+ }
+ }
+
+ /* And finally try a literal 256-color-mode number */
+ val = strtol(name, &end, 10);
+ if (end - name == len) {
+ /*
+ * Allow "-1" as an alias for "normal", but other negative
+ * numbers are bogus.
+ */
+ if (val < -1)
+ ; /* fall through to error */
+ else if (val < 0) {
+ out->type = COLOR_NORMAL;
+ return 0;
+ /* Rewrite low numbers as more-portable standard colors. */
+ } else if (val < 8) {
+ out->type = COLOR_ANSI;
+ out->value = val;
+ } else if (val < 256) {
+ out->type = COLOR_256;
+ out->value = val;
+ return 0;
+ }
}
- i = strtol(name, &end, 10);
- if (end - name == len && i >= -1 && i <= 255)
- return i;
- return -2;
+
+ return -1;
}
static int parse_attr(const char *name, int len)
{
- static const int attr_values[] = { 1, 2, 4, 5, 7 };
+ static const int attr_values[] = { 1, 2, 4, 5, 7,
+ 22, 22, 24, 25, 27 };
static const char * const attr_names[] = {
- "bold", "dim", "ul", "blink", "reverse"
+ "bold", "dim", "ul", "blink", "reverse",
+ "nobold", "nodim", "noul", "noblink", "noreverse"
};
int i;
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
return color_parse_mem(value, strlen(value), dst);
}
+/*
+ * Write the ANSI color codes for "c" to "out"; the string should
+ * already have the ANSI escape code in it. "out" should have enough
+ * space in it to fit any color.
+ */
+static char *color_output(char *out, const struct color *c, char type)
+{
+ switch (c->type) {
+ case COLOR_UNSPECIFIED:
+ case COLOR_NORMAL:
+ break;
+ case COLOR_ANSI:
+ *out++ = type;
+ *out++ = '0' + c->value;
+ break;
+ case COLOR_256:
+ out += sprintf(out, "%c8;5;%d", type, c->value);
+ break;
+ case COLOR_RGB:
+ out += sprintf(out, "%c8;2;%d;%d;%d", type,
+ c->red, c->green, c->blue);
+ break;
+ }
+ return out;
+}
+
+static int color_empty(const struct color *c)
+{
+ return c->type <= COLOR_NORMAL;
+}
+
int color_parse_mem(const char *value, int value_len, char *dst)
{
const char *ptr = value;
int len = value_len;
unsigned int attr = 0;
- int fg = -2;
- int bg = -2;
+ struct color fg = { COLOR_UNSPECIFIED };
+ struct color bg = { COLOR_UNSPECIFIED };
if (!strncasecmp(value, "reset", len)) {
strcpy(dst, GIT_COLOR_RESET);
/* [fg [bg]] [attr]... */
while (len > 0) {
const char *word = ptr;
+ struct color c;
int val, wordlen = 0;
while (len > 0 && !isspace(word[wordlen])) {
len--;
}
- val = parse_color(word, wordlen);
- if (val >= -1) {
- if (fg == -2) {
- fg = val;
+ if (!parse_color(&c, word, wordlen)) {
+ if (fg.type == COLOR_UNSPECIFIED) {
+ fg = c;
continue;
}
- if (bg == -2) {
- bg = val;
+ if (bg.type == COLOR_UNSPECIFIED) {
+ bg = c;
continue;
}
goto bad;
goto bad;
}
- if (attr || fg >= 0 || bg >= 0) {
+ if (attr || !color_empty(&fg) || !color_empty(&bg)) {
int sep = 0;
int i;
attr &= ~bit;
if (sep++)
*dst++ = ';';
- *dst++ = '0' + i;
+ dst += sprintf(dst, "%d", i);
}
- if (fg >= 0) {
+ if (!color_empty(&fg)) {
if (sep++)
*dst++ = ';';
- if (fg < 8) {
- *dst++ = '3';
- *dst++ = '0' + fg;
- } else {
- dst += sprintf(dst, "38;5;%d", fg);
- }
+ /* foreground colors are all in the 3x range */
+ dst = color_output(dst, &fg, '3');
}
- if (bg >= 0) {
+ if (!color_empty(&bg)) {
if (sep++)
*dst++ = ';';
- if (bg < 8) {
- *dst++ = '4';
- *dst++ = '0' + bg;
- } else {
- dst += sprintf(dst, "48;5;%d", bg);
- }
+ /* background colors are all in the 4x range */
+ dst = color_output(dst, &bg, '4');
}
*dst++ = 'm';
}
/*
* The maximum length of ANSI color sequence we would generate:
* - leading ESC '[' 2
- * - attr + ';' 2 * 8 (e.g. "1;")
- * - fg color + ';' 9 (e.g. "38;5;2xx;")
- * - fg color + ';' 9 (e.g. "48;5;2xx;")
+ * - attr + ';' 3 * 10 (e.g. "1;")
+ * - fg color + ';' 17 (e.g. "38;2;255;255;255;")
+ * - bg color + ';' 17 (e.g. "48;2;255;255;255;")
* - terminating 'm' NUL 2
*
* The above overcounts attr (we only use 5 not 8) and one semicolon
* but it is close enough.
*/
-#define COLOR_MAXLEN 40
+#define COLOR_MAXLEN 70
/*
* IMPORTANT: Due to the way these color codes are emulated on Windows,
for (j = ret; j; j = j->next) {
struct commit_list *bases;
- bases = get_merge_bases(i->item, j->item, 1);
+ bases = get_merge_bases(i->item, j->item);
if (!new)
new = bases;
else
return filled;
}
-struct commit_list *get_merge_bases_many(struct commit *one,
- int n,
- struct commit **twos,
- int cleanup)
+static struct commit_list *get_merge_bases_many_0(struct commit *one,
+ int n,
+ struct commit **twos,
+ int cleanup)
{
struct commit_list *list;
struct commit **rslt;
return result;
}
-struct commit_list *get_merge_bases(struct commit *one, struct commit *two,
- int cleanup)
+struct commit_list *get_merge_bases_many(struct commit *one,
+ int n,
+ struct commit **twos)
{
- return get_merge_bases_many(one, 1, &two, cleanup);
+ return get_merge_bases_many_0(one, n, twos, 1);
+}
+
+struct commit_list *get_merge_bases_many_dirty(struct commit *one,
+ int n,
+ struct commit **twos)
+{
+ return get_merge_bases_many_0(one, n, twos, 0);
+}
+
+struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
+{
+ return get_merge_bases_many_0(one, 1, &two, 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;
+}
int register_commit_graft(struct commit_graft *, int);
struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
-extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
-extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
+extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
+extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
+/* To be used only when object flags after this call no longer matter */
+extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
+
/* largest positive number a signed 32-bit integer can contain */
#define INFINITE_DEPTH 0x7fffffff
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);
--- /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;
+}
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;
}
LIBC_CONTAINS_LIBINTL = YesPlease
HAVE_DEV_TTY = YesPlease
HAVE_CLOCK_GETTIME = YesPlease
+ HAVE_CLOCK_MONOTONIC = YesPlease
endif
ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_ALLOCA_H = YesPlease
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
[#include <sys/time.h>])
GIT_CONF_SUBST([NO_STRUCT_ITIMERVAL])
#
+# Define USE_ST_TIMESPEC=YesPlease when stat.st_mtimespec.tv_nsec exists.
+# Define NO_NSEC=YesPlease when neither stat.st_mtim.tv_nsec nor
+# stat.st_mtimespec.tv_nsec exists.
+AC_CHECK_MEMBER([struct stat.st_mtimespec.tv_nsec])
+AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec])
+if test x$ac_cv_member_struct_stat_st_mtimespec_tv_nsec = xyes; then
+ USE_ST_TIMESPEC=YesPlease
+ GIT_CONF_SUBST([USE_ST_TIMESPEC])
+elif test x$ac_cv_member_struct_stat_st_mtim_tv_nsec != xyes; then
+ NO_NSEC=YesPlease
+ GIT_CONF_SUBST([NO_NSEC])
+fi
+#
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
AC_CHECK_MEMBER(struct dirent.d_ino,
[NO_D_INO_IN_DIRENT=],
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.
[CHARSET_LIB=-lcharset])])
GIT_CONF_SUBST([CHARSET_LIB])
#
+# Define NO_HMAC_CTX_CLEANUP=YesPlease if HMAC_CTX_cleanup is missing.
+AC_CHECK_LIB([crypto], [HMAC_CTX_cleanup],
+ [], [GIT_CONF_SUBST([NO_HMAC_CTX_CLEANUP], [YesPlease])])
+#
+# Define HAVE_CLOCK_GETTIME=YesPlease if clock_gettime is available.
+GIT_CHECK_FUNC(clock_gettime,
+ [HAVE_CLOCK_GETTIME=YesPlease],
+ [HAVE_CLOCK_GETTIME=])
+GIT_CONF_SUBST([HAVE_CLOCK_GETTIME])
+
+AC_DEFUN([CLOCK_MONOTONIC_SRC], [
+AC_LANG_PROGRAM([[
+#include <time.h>
+clockid_t id = CLOCK_MONOTONIC;
+]])])
+
+#
+# Define HAVE_CLOCK_MONOTONIC=YesPlease if CLOCK_MONOTONIC is available.
+AC_MSG_CHECKING([for CLOCK_MONOTONIC])
+AC_COMPILE_IFELSE([CLOCK_MONOTONIC_SRC],
+ [AC_MSG_RESULT([yes])
+ HAVE_CLOCK_MONOTONIC=YesPlease],
+ [AC_MSG_RESULT([no])
+ HAVE_CLOCK_MONOTONIC=])
+GIT_CONF_SUBST([HAVE_CLOCK_MONOTONIC])
+#
# Define NO_SETITIMER if you don't have setitimer.
GIT_CHECK_FUNC(setitimer,
[NO_SETITIMER=],
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;
#
# To use these routines:
#
-# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
+# 1) Copy this file to somewhere (e.g. ~/.git-completion.bash).
# 2) Add the following line to your .bashrc/.zshrc:
-# source ~/.git-completion.sh
+# source ~/.git-completion.bash
# 3) Consider changing your PS1 to also show the current branch,
# see git-prompt.sh for details.
#
--committer-date-is-author-date --ignore-date
--ignore-whitespace --whitespace=
--autosquash --fork-point --no-fork-point
+ --autostash
"
return
__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 ()
#
# If your script is somewhere else, you can configure it on your ~/.zshrc:
#
-# zstyle ':completion:*:*:git:*' script ~/.git-completion.sh
+# zstyle ':completion:*:*:git:*' script ~/.git-completion.zsh
#
# The recommended way to install this script is to copy to '~/.zsh/_git', and
# then add the following to your ~/.zshrc file:
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd.
+#
+# If you would like __git_ps1 to do nothing in the case when the current
+# directory is set up to be ignored by git, then set
+# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
+# repository level by setting bash.hideIfPwdIgnored to "false".
# check whether printf supports -v
__git_printf_supports_v=
__git_eread ()
{
- f="$1"
+ local f="$1"
shift
test -r "$f" && read "$@" <"$f"
}
# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
__git_ps1 ()
{
+ # preserve exit status
+ local exit=$?
local pcmode=no
local detached=no
local ps1pc_start='\u@\h:\w '
ps1pc_start="$1"
ps1pc_end="$2"
printf_format="${3:-$printf_format}"
+ # set PS1 to a plain prompt so that we can
+ # simply return early if the prompt should not
+ # be decorated
+ PS1="$ps1pc_start$ps1pc_end"
;;
0|1) printf_format="${1:-$printf_format}"
;;
- *) return
+ *) return $exit
;;
esac
rev_parse_exit_code="$?"
if [ -z "$repo_info" ]; then
- if [ $pcmode = yes ]; then
- #In PC mode PS1 always needs to be set
- PS1="$ps1pc_start$ps1pc_end"
- fi
- return
+ return $exit
fi
local short_sha
local inside_gitdir="${repo_info##*$'\n'}"
local g="${repo_info%$'\n'*}"
+ if [ "true" = "$inside_worktree" ] &&
+ [ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
+ [ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
+ git check-ignore -q .
+ then
+ return $exit
+ fi
+
local r=""
local b=""
local step=""
else
local head=""
if ! __git_eread "$g/HEAD" head; then
- if [ $pcmode = yes ]; then
- PS1="$ps1pc_start$ps1pc_end"
- fi
- return
+ return $exit
fi
# is it a symbolic ref?
b="${head#ref: }"
else
printf -- "$printf_format" "$gitstring"
fi
+
+ return $exit
}
diff = diff-highlight | less
---------------------------------------------
+
+Color Config
+------------
+
+You can configure the highlight colors and attributes using git's
+config. The colors for "old" and "new" lines can be specified
+independently. There are two "modes" of configuration:
+
+ 1. You can specify a "highlight" color and a matching "reset" color.
+ This will retain any existing colors in the diff, and apply the
+ "highlight" and "reset" colors before and after the highlighted
+ portion.
+
+ 2. You can specify a "normal" color and a "highlight" color. In this
+ case, existing colors are dropped from that line. The non-highlighted
+ bits of the line get the "normal" color, and the highlights get the
+ "highlight" color.
+
+If no "new" colors are specified, they default to the "old" colors. If
+no "old" colors are specified, the default is to reverse the foreground
+and background for highlighted portions.
+
+Examples:
+
+---------------------------------------------
+# Underline highlighted portions
+[color "diff-highlight"]
+oldHighlight = ul
+oldReset = noul
+---------------------------------------------
+
+---------------------------------------------
+# Varying background intensities
+[color "diff-highlight"]
+oldNormal = "black #f8cbcb"
+oldHighlight = "black #ffaaaa"
+newNormal = "black #cbeecb"
+newHighlight = "black #aaffaa"
+---------------------------------------------
+
+
Bugs
----
# Highlight by reversing foreground and background. You could do
# other things like bold or underline if you prefer.
-my $HIGHLIGHT = "\x1b[7m";
-my $UNHIGHLIGHT = "\x1b[27m";
+my @OLD_HIGHLIGHT = (
+ color_config('color.diff-highlight.oldnormal'),
+ color_config('color.diff-highlight.oldhighlight', "\x1b[7m"),
+ color_config('color.diff-highlight.oldreset', "\x1b[27m")
+);
+my @NEW_HIGHLIGHT = (
+ color_config('color.diff-highlight.newnormal', $OLD_HIGHLIGHT[0]),
+ color_config('color.diff-highlight.newhighlight', $OLD_HIGHLIGHT[1]),
+ color_config('color.diff-highlight.newreset', $OLD_HIGHLIGHT[2])
+);
+
+my $RESET = "\x1b[m";
my $COLOR = qr/\x1b\[[0-9;]*m/;
my $BORING = qr/$COLOR|\s/;
exit 0;
+# Ideally we would feed the default as a human-readable color to
+# git-config as the fallback value. But diff-highlight does
+# not otherwise depend on git at all, and there are reports
+# of it being used in other settings. Let's handle our own
+# fallback, which means we will work even if git can't be run.
+sub color_config {
+ my ($key, $default) = @_;
+ my $s = `git config --get-color $key 2>/dev/null`;
+ return length($s) ? $s : $default;
+}
+
sub show_hunk {
my ($a, $b) = @_;
}
if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) {
- return highlight_line(\@a, $pa, $sa),
- highlight_line(\@b, $pb, $sb);
+ return highlight_line(\@a, $pa, $sa, \@OLD_HIGHLIGHT),
+ highlight_line(\@b, $pb, $sb, \@NEW_HIGHLIGHT);
}
else {
return join('', @a),
}
sub highlight_line {
- my ($line, $prefix, $suffix) = @_;
-
- return join('',
- @{$line}[0..($prefix-1)],
- $HIGHLIGHT,
- @{$line}[$prefix..$suffix],
- $UNHIGHLIGHT,
- @{$line}[($suffix+1)..$#$line]
- );
+ my ($line, $prefix, $suffix, $theme) = @_;
+
+ my $start = join('', @{$line}[0..($prefix-1)]);
+ my $mid = join('', @{$line}[$prefix..$suffix]);
+ my $end = join('', @{$line}[($suffix+1)..$#$line]);
+
+ # If we have a "normal" color specified, then take over the whole line.
+ # Otherwise, we try to just manipulate the highlighted bits.
+ if (defined $theme->[0]) {
+ s/$COLOR//g for ($start, $mid, $end);
+ chomp $end;
+ return join('',
+ $theme->[0], $start, $RESET,
+ $theme->[1], $mid, $RESET,
+ $theme->[0], $end, $RESET,
+ "\n"
+ );
+ } else {
+ return join('',
+ $start,
+ $theme->[1], $mid, $theme->[2],
+ $end
+ );
+ }
}
# Pairs are interesting to highlight only if we are going to end up
changes into the latest <commit>. With '--squash',
creates only one commit that contains all the changes,
rather than merging in the entire history.
-
- If you use '--squash', the merge direction doesn't
- always have to be forward; you can use this command to
- go back in time from v2.5 to v2.4, for example. If your
- merge introduces a conflict, you can resolve it in the
- usual ways.
++
+If you use '--squash', the merge direction doesn't always have to be
+forward; you can use this command to go back in time from v2.5 to v2.4,
+for example. If your merge introduces a conflict, you can resolve it in
+the usual ways.
pull::
Exactly like 'merge', but parallels 'git pull' in that
contents of <prefix> at the root of the project instead
of in a subdirectory. Thus, the newly created history
is suitable for export as a separate git repository.
-
- After splitting successfully, a single commit id is
- printed to stdout. This corresponds to the HEAD of the
- newly created tree, which you can manipulate however you
- want.
-
- Repeated splits of exactly the same history are
- guaranteed to be identical (i.e. to produce the same
- commit ids). Because of this, if you add new commits
- and then re-split, the new commits will be attached as
- commits on top of the history you generated last time,
- so 'git merge' and friends will work as expected.
-
- Note that if you use '--squash' when you merge, you
- should usually not just '--rejoin' when you split.
++
+After splitting successfully, a single commit id is printed to stdout.
+This corresponds to the HEAD of the newly created tree, which you can
+manipulate however you want.
++
+Repeated splits of exactly the same history are guaranteed to be
+identical (i.e. to produce the same commit ids). Because of this, if
+you add new commits and then re-split, the new commits will be attached
+as commits on top of the history you generated last time, so 'git merge'
+and friends will work as expected.
++
+Note that if you use '--squash' when you merge, you should usually not
+just '--rejoin' when you split.
OPTIONS
--squash::
This option is only valid for add, merge, push and pull
commands.
-
- Instead of merging the entire history from the subtree
- project, produce only a single commit that contains all
- the differences you want to merge, and then merge that
- new commit into your project.
-
- Using this option helps to reduce log clutter. People
- rarely want to see every change that happened between
- v1.0 and v1.1 of the library they're using, since none of the
- interim versions were ever included in their application.
-
- Using '--squash' also helps avoid problems when the same
- subproject is included multiple times in the same
- project, or is removed and then re-added. In such a
- case, it doesn't make sense to combine the histories
- anyway, since it's unclear which part of the history
- belongs to which subtree.
-
- Furthermore, with '--squash', you can switch back and
- forth between different versions of a subtree, rather
- than strictly forward. 'git subtree merge --squash'
- always adjusts the subtree to match the exactly
- specified commit, even if getting to that commit would
- require undoing some changes that were added earlier.
-
- Whether or not you use '--squash', changes made in your
- local repository remain intact and can be later split
- and send upstream to the subproject.
++
+Instead of merging the entire history from the subtree project, produce
+only a single commit that contains all the differences you want to
+merge, and then merge that new commit into your project.
++
+Using this option helps to reduce log clutter. People rarely want to see
+every change that happened between v1.0 and v1.1 of the library they're
+using, since none of the interim versions were ever included in their
+application.
++
+Using '--squash' also helps avoid problems when the same subproject is
+included multiple times in the same project, or is removed and then
+re-added. In such a case, it doesn't make sense to combine the
+histories anyway, since it's unclear which part of the history belongs
+to which subtree.
++
+Furthermore, with '--squash', you can switch back and forth between
+different versions of a subtree, rather than strictly forward. 'git
+subtree merge --squash' always adjusts the subtree to match the exactly
+specified commit, even if getting to that commit would require undoing
+some changes that were added earlier.
++
+Whether or not you use '--squash', changes made in your local repository
+remain intact and can be later split and send upstream to the
+subproject.
OPTIONS FOR split
-----------------
--annotate=<annotation>::
This option is only valid for the split command.
-
- When generating synthetic history, add <annotation> as a
- prefix to each commit message. Since we're creating new
- commits with the same commit message, but possibly
- different content, from the original commits, this can help
- to differentiate them and avoid confusion.
-
- Whenever you split, you need to use the same
- <annotation>, or else you don't have a guarantee that
- the new re-created history will be identical to the old
- one. That will prevent merging from working correctly.
- git subtree tries to make it work anyway, particularly
- if you use --rejoin, but it may not always be effective.
++
+When generating synthetic history, add <annotation> as a prefix to each
+commit message. Since we're creating new commits with the same commit
+message, but possibly different content, from the original commits, this
+can help to differentiate them and avoid confusion.
++
+Whenever you split, you need to use the same <annotation>, or else you
+don't have a guarantee that the new re-created history will be identical
+to the old one. That will prevent merging from working correctly. git
+subtree tries to make it work anyway, particularly if you use --rejoin,
+but it may not always be effective.
-b <branch>::
--branch=<branch>::
This option is only valid for the split command.
-
- After generating the synthetic history, create a new
- branch called <branch> that contains the new history.
- This is suitable for immediate pushing upstream.
- <branch> must not already exist.
++
+After generating the synthetic history, create a new branch called
+<branch> that contains the new history. This is suitable for immediate
+pushing upstream. <branch> must not already exist.
--ignore-joins::
This option is only valid for the split command.
-
- If you use '--rejoin', git subtree attempts to optimize
- its history reconstruction to generate only the new
- commits since the last '--rejoin'. '--ignore-join'
- disables this behaviour, forcing it to regenerate the
- entire history. In a large project, this can take a
- long time.
++
+If you use '--rejoin', git subtree attempts to optimize its history
+reconstruction to generate only the new commits since the last
+'--rejoin'. '--ignore-join' disables this behaviour, forcing it to
+regenerate the entire history. In a large project, this can take a long
+time.
--onto=<onto>::
This option is only valid for the split command.
-
- If your subtree was originally imported using something
- other than git subtree, its history may not match what
- git subtree is expecting. In that case, you can specify
- the commit id <onto> that corresponds to the first
- revision of the subproject's history that was imported
- into your project, and git subtree will attempt to build
- its history from there.
-
- If you used 'git subtree add', you should never need
- this option.
++
+If your subtree was originally imported using something other than git
+subtree, its history may not match what git subtree is expecting. In
+that case, you can specify the commit id <onto> that corresponds to the
+first revision of the subproject's history that was imported into your
+project, and git subtree will attempt to build its history from there.
++
+If you used 'git subtree add', you should never need this option.
--rejoin::
This option is only valid for the split command.
-
- After splitting, merge the newly created synthetic
- history back into your main project. That way, future
- splits can search only the part of history that has
- been added since the most recent --rejoin.
-
- If your split commits end up merged into the upstream
- subproject, and then you want to get the latest upstream
- version, this will allow git's merge algorithm to more
- intelligently avoid conflicts (since it knows these
- synthetic commits are already part of the upstream
- repository).
-
- Unfortunately, using this option results in 'git log'
- showing an extra copy of every new commit that was
- created (the original, and the synthetic one).
-
- If you do all your merges with '--squash', don't use
- '--rejoin' when you split, because you don't want the
- subproject's history to be part of your project anyway.
++
+After splitting, merge the newly created synthetic history back into
+your main project. That way, future splits can search only the part of
+history that has been added since the most recent --rejoin.
++
+If your split commits end up merged into the upstream subproject, and
+then you want to get the latest upstream version, this will allow git's
+merge algorithm to more intelligently avoid conflicts (since it knows
+these synthetic commits are already part of the upstream repository).
++
+Unfortunately, using this option results in 'git log' showing an extra
+copy of every new commit that was created (the original, and the
+synthetic one).
++
+If you do all your merges with '--squash', don't use '--rejoin' when you
+split, because you don't want the subproject's history to be part of
+your project anyway.
EXAMPLE 1. Add command
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;
return 0;
}
-static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
+static int match_multi_number(unsigned long num, char c, const char *date,
+ char *end, struct tm *tm, time_t now)
{
- time_t now;
struct tm now_tm;
struct tm *refuse_future;
long num2, num3;
case '-':
case '/':
case '.':
- now = time(NULL);
+ if (!now)
+ now = time(NULL);
refuse_future = NULL;
if (gmtime_r(&now, &now_tm))
refuse_future = &now_tm;
if (num > 70) {
/* yyyy-mm-dd? */
- if (is_date(num, num2, num3, refuse_future, now, tm))
+ if (is_date(num, num2, num3, NULL, now, tm))
break;
/* yyyy-dd-mm? */
- if (is_date(num, num3, num2, refuse_future, now, tm))
+ if (is_date(num, num3, num2, NULL, now, tm))
break;
}
/* Our eastern European friends say dd.mm.yy[yy]
case '/':
case '-':
if (isdigit(end[1])) {
- int match = match_multi_number(num, *end, date, end, tm);
+ int match = match_multi_number(num, *end, date, end, tm, 0);
if (match)
return match;
}
return end;
}
-static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
+static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
+ time_t now)
{
char *end;
unsigned long number = strtoul(date, &end, 10);
case '/':
case '-':
if (isdigit(end[1])) {
- int match = match_multi_number(number, *end, date, end, tm);
+ int match = match_multi_number(number, *end, date, end,
+ tm, now);
if (match)
return date + match;
}
date++;
if (isdigit(c)) {
pending_number(&tm, &number);
- date = approxidate_digit(date-1, &tm, &number);
+ date = approxidate_digit(date-1, &tm, &number, time_sec);
touched = 1;
continue;
}
dp = diff_queue(outq, d->one, c->two);
dp->score = p->score;
+ /*
+ * We will be one extra user of the same src side of the
+ * broken pair, if it was used as the rename source for other
+ * paths elsewhere. Increment to mark that the path stays
+ * in the resulting tree.
+ */
+ d->one->rename_used++;
diff_free_filespec_data(d->two);
diff_free_filespec_data(c->one);
free(d);
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);
}
strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
if (check_refname_format(sb.buf, 0))
- error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %s", buffer);
+ error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %.*s",
+ (int)(eol - buffer), buffer);
buffer = eol + 1;
if (!skip_prefix(buffer, "tagger ", &buffer))
$patch_mode_flavour{TARGET},
" [y,n,q,a,d,/$other,?]? ";
my $line = prompt_single_character;
+ last unless defined $line;
if ($line) {
if ($line =~ /^y/i) {
$hunk[$ix]{USE} = 1;
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
check_expected_revs "$rev" ;;
2,bad|*,good|*,skip)
shift
- eval=''
+ hash_list=''
for rev in "$@"
do
sha=$(git rev-parse --verify "$rev^{commit}") ||
die "$(eval_gettext "Bad rev input: \$rev")"
- eval="$eval bisect_write '$state' '$sha'; "
+ hash_list="$hash_list $sha"
done
- eval "$eval"
- check_expected_revs "$@" ;;
+ for rev in $hash_list
+ do
+ bisect_write "$state" "$rev"
+ done
+ check_expected_revs $hash_list ;;
*,bad)
die "$(gettext "'git bisect bad' can take only one argument.")" ;;
*)
# 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
#endif
#ifndef NO_OPENSSL
+#define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
#include <openssl/ssl.h>
#include <openssl/err.h>
+#undef MAC_OS_X_VERSION_MIN_REQUIRED
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
+#ifdef NO_HMAC_CTX_CLEANUP
+#define HMAC_CTX_cleanup HMAC_cleanup
+#endif
#endif
/* On most systems <netdb.h> would have given us this, but
#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))
test -n "$autosquash" && rearrange_squash "$todo"
test -n "$cmd" && add_exec_commands "$todo"
+todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
+
cat >>"$todo" <<EOF
-$comment_char Rebase $shortrevisions onto $shortonto
+$comment_char Rebase $shortrevisions onto $shortonto ($todocount TODO item(s))
EOF
append_todo_help
git stripspace --comment-lines >>"$todo" <<\EOF
--[no-]bcc <str> * Email Bcc:
--subject <str> * Email "Subject:"
--in-reply-to <str> * Email "In-Reply-To:"
+ --[no-]xmailer * Add "X-Mailer:" header (default).
--[no-]annotate * Review each patch that will be sent in an editor.
--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 $smtp;
my $auth;
+# Regexes for RFC 2047 productions.
+my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/;
+my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
+my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
+
# Variables we fill in automatically, or via prompting:
my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
$initial_reply_to,$initial_subject,@files,
- $author,$sender,$smtp_authpass,$annotate,$compose,$time);
+ $author,$sender,$smtp_authpass,$annotate,$use_xmailer,$compose,$time);
my $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()
"signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated
"validate" => [\$validate, 1],
"multiedit" => [\$multiedit, undef],
- "annotate" => [\$annotate, undef]
+ "annotate" => [\$annotate, undef],
+ "xmailer" => [\$use_xmailer, 1]
);
my %config_settings = (
"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,
"force" => \$force,
+ "xmailer!" => \$use_xmailer,
);
usage() if $help;
sub unquote_rfc2047 {
local ($_) = @_;
- my $encoding;
- s{=\?([^?]+)\?q\?(.*?)\?=}{
- $encoding = $1;
- my $e = $2;
- $e =~ s/_/ /g;
- $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg;
- $e;
+ my $charset;
+ my $sep = qr/[ \t]+/;
+ s{$re_encoded_word(?:$sep$re_encoded_word)*}{
+ my @words = split $sep, $&;
+ foreach (@words) {
+ m/$re_encoded_word/;
+ $charset = $1;
+ my $encoding = $2;
+ my $text = $3;
+ if ($encoding eq 'q' || $encoding eq 'Q') {
+ $_ = $text;
+ s/_/ /g;
+ s/=([0-9A-F]{2})/chr(hex($1))/egi;
+ } else {
+ # other encodings not supported yet
+ }
+ }
+ join '', @words;
}eg;
- return wantarray ? ($_, $encoding) : $_;
+ return wantarray ? ($_, $charset) : $_;
}
sub quote_rfc2047 {
sub is_rfc2047_quoted {
my $s = shift;
- my $token = qr/[^][()<>@,;:"\/?.= \000-\037\177-\377]+/;
- my $encoded_text = qr/[!->@-~]+/;
length($s) <= 75 &&
- $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
+ $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
}
sub subject_needs_rfc2047_quoting {
Subject: $subject
Date: $date
Message-Id: $message_id
-X-Mailer: git-send-email $gitversion
";
+ if ($use_xmailer) {
+ $header .= "X-Mailer: git-send-email $gitversion\n";
+ }
if ($reply_to) {
$header .= "In-Reply-To: $reply_to\n";
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"
}
$_before, $_after,
$_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
- $_commit_url, $_tag, $_merge_info, $_interactive);
+ $_commit_url, $_tag, $_merge_info, $_interactive, $_set_svn_props);
# This is a refactoring artifact so Git::SVN can get at this git-svn switch.
sub opt_prefix { return $_prefix || '' }
'dry-run|n' => \$_dry_run,
'fetch-all|all' => \$_fetch_all,
'commit-url=s' => \$_commit_url,
+ 'set-svn-props=s' => \$_set_svn_props,
'revision|r=i' => \$_revision,
'no-rebase' => \$_no_rebase,
'mergeinfo=s' => \$_merge_info,
'propget' => [ \&cmd_propget,
'Print the value of a property on a file or directory',
{ 'revision|r=i' => \$_revision } ],
+ 'propset' => [ \&cmd_propset,
+ 'Set the value of a property on a file or directory - will be set on commit',
+ {} ],
'proplist' => [ \&cmd_proplist,
'List all properties of a file or directory',
{ 'revision|r=i' => \$_revision } ],
print $props->{$prop} . "\n";
}
+# cmd_propset (PROPNAME, PROPVAL, PATH)
+# ------------------------
+# Adjust the SVN property PROPNAME to PROPVAL for PATH.
+sub cmd_propset {
+ my ($propname, $propval, $path) = @_;
+ $path = '.' if not defined $path;
+ $path = $cmd_dir_prefix . $path;
+ usage(1) if not defined $propname;
+ usage(1) if not defined $propval;
+ my $file = basename($path);
+ my $dn = dirname($path);
+ my $cur_props = Git::SVN::Editor::check_attr( "svn-properties", $path );
+ my @new_props;
+ if (!$cur_props || $cur_props eq "unset" || $cur_props eq "" || $cur_props eq "set") {
+ push @new_props, "$propname=$propval";
+ } else {
+ # TODO: handle combining properties better
+ my @props = split(/;/, $cur_props);
+ my $replaced_prop;
+ foreach my $prop (@props) {
+ # Parse 'name=value' syntax and set the property.
+ if ($prop =~ /([^=]+)=(.*)/) {
+ my ($n,$v) = ($1,$2);
+ if ($n eq $propname) {
+ $v = $propval;
+ $replaced_prop = 1;
+ }
+ push @new_props, "$n=$v";
+ }
+ }
+ if (!$replaced_prop) {
+ push @new_props, "$propname=$propval";
+ }
+ }
+ my $attrfile = "$dn/.gitattributes";
+ open my $attrfh, '>>', $attrfile or die "Can't open $attrfile: $!\n";
+ # TODO: don't simply append here if $file already has svn-properties
+ my $new_props = join(';', @new_props);
+ print $attrfh "$file svn-properties=$new_props\n" or
+ die "write to $attrfile: $!\n";
+ close $attrfh or die "close $attrfile: $!\n";
+}
+
# cmd_proplist (PATH)
# -------------------
# Print the list of SVN properties for PATH.
#include "builtin.h"
-#include "cache.h"
#include "exec_cmd.h"
#include "help.h"
-#include "quote.h"
#include "run-command.h"
-#include "commit.h"
const char git_usage_string[] =
"git [--version] [--help] [-C <path>] [-c name=value]\n"
#include "credential.h"
#include "exec_cmd.h"
#include "run-command.h"
+#include "parse-options.h"
#ifdef NO_OPENSSL
typedef void *SSL;
#endif
+#ifdef USE_CURL_FOR_IMAP_SEND
+#include "http.h"
+#endif
+
+static int verbosity;
+static int use_curl; /* strictly opt in */
-static const char imap_send_usage[] = "git imap-send < <mbox>";
+static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
+
+static struct option imap_send_options[] = {
+ OPT__VERBOSITY(&verbosity),
+ OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
+ OPT_END()
+};
#undef DRV_OK
#define DRV_OK 0
#define DRV_BOX_BAD -2
#define DRV_STORE_BAD -3
-static int Verbose, Quiet;
-
__attribute__((format (printf, 1, 2)))
static void imap_info(const char *, ...);
__attribute__((format (printf, 1, 2)))
if (b->buf[b->offset + 1] == '\n') {
b->buf[b->offset] = 0; /* terminate the string */
b->offset += 2; /* next line */
- if (Verbose)
+ if (0 < verbosity)
puts(*s);
return 0;
}
{
va_list va;
- if (!Quiet) {
+ if (0 <= verbosity) {
va_start(va, msg);
vprintf(msg, va);
va_end(va);
{
va_list va;
- if (Quiet < 2) {
+ if (-2 < verbosity) {
va_start(va, msg);
vfprintf(stderr, msg, va);
va_end(va);
cmd->tag, cmd->cmd, cmd->cb.dlen,
CAP(LITERALPLUS) ? "+" : "");
- if (Verbose) {
+ if (0 < verbosity) {
if (imap->num_in_progress)
printf("(%d in progress) ", imap->num_in_progress);
if (!starts_with(cmd->cmd, "LOGIN"))
git_config_get_string("imap.authmethod", &server.auth_method);
}
-int main(int argc, char **argv)
+static int append_msgs_to_imap(struct imap_server_conf *server,
+ struct strbuf* all_msgs, int total)
{
- struct strbuf all_msgs = STRBUF_INIT;
struct strbuf msg = STRBUF_INIT;
struct imap_store *ctx = NULL;
int ofs = 0;
int r;
- int total, n = 0;
+ int n = 0;
+
+ ctx = imap_open_store(server, server->folder);
+ if (!ctx) {
+ fprintf(stderr, "failed to open store\n");
+ return 1;
+ }
+ ctx->name = server->folder;
+
+ fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
+ while (1) {
+ unsigned percent = n * 100 / total;
+
+ fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
+
+ if (!split_msg(all_msgs, &msg, &ofs))
+ break;
+ if (server->use_html)
+ wrap_in_html(&msg);
+ r = imap_store_msg(ctx, &msg);
+ if (r != DRV_OK)
+ break;
+ n++;
+ }
+ fprintf(stderr, "\n");
+
+ imap_close_store(ctx);
+
+ return 0;
+}
+
+#ifdef USE_CURL_FOR_IMAP_SEND
+static CURL *setup_curl(struct imap_server_conf *srvc)
+{
+ CURL *curl;
+ struct strbuf path = STRBUF_INIT;
+
+ if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
+ die("curl_global_init failed");
+
+ curl = curl_easy_init();
+
+ if (!curl)
+ die("curl_easy_init failed");
+
+ curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
+
+ strbuf_addstr(&path, server.host);
+ if (!path.len || path.buf[path.len - 1] != '/')
+ strbuf_addch(&path, '/');
+ strbuf_addstr(&path, server.folder);
+
+ curl_easy_setopt(curl, CURLOPT_URL, path.buf);
+ strbuf_release(&path);
+ curl_easy_setopt(curl, CURLOPT_PORT, server.port);
+
+ if (server.auth_method) {
+ struct strbuf auth = STRBUF_INIT;
+ strbuf_addstr(&auth, "AUTH=");
+ strbuf_addstr(&auth, server.auth_method);
+ curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
+ strbuf_release(&auth);
+ }
+
+ if (!server.use_ssl)
+ curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
+
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);
+
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
+
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+
+ if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ return curl;
+}
+
+static int curl_append_msgs_to_imap(struct imap_server_conf *server,
+ struct strbuf* all_msgs, int total) {
+ int ofs = 0;
+ int n = 0;
+ struct buffer msgbuf = { STRBUF_INIT, 0 };
+ CURL *curl;
+ CURLcode res = CURLE_OK;
+
+ curl = setup_curl(server);
+ curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
+
+ fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
+ while (1) {
+ unsigned percent = n * 100 / total;
+ int prev_len;
+
+ fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
+
+ prev_len = msgbuf.buf.len;
+ if (!split_msg(all_msgs, &msgbuf.buf, &ofs))
+ break;
+ if (server->use_html)
+ wrap_in_html(&msgbuf.buf);
+ lf_to_crlf(&msgbuf.buf);
+
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
+ (curl_off_t)(msgbuf.buf.len-prev_len));
+
+ res = curl_easy_perform(curl);
+
+ if(res != CURLE_OK) {
+ fprintf(stderr, "curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(res));
+ break;
+ }
+
+ n++;
+ }
+ fprintf(stderr, "\n");
+
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ struct strbuf all_msgs = STRBUF_INIT;
+ int total;
int nongit_ok;
git_extract_argv0_path(argv[0]);
git_setup_gettext();
- if (argc != 1)
- usage(imap_send_usage);
-
setup_git_directory_gently(&nongit_ok);
git_imap_config();
+ argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
+
+ if (argc)
+ usage_with_options(imap_send_usage, imap_send_options);
+
+#ifndef USE_CURL_FOR_IMAP_SEND
+ if (use_curl) {
+ warning("--use-curl not supported in this build");
+ use_curl = 0;
+ }
+#endif
+
if (!server.port)
server.port = server.use_ssl ? 993 : 143;
}
/* write it to the imap server */
- ctx = imap_open_store(&server, server.folder);
- if (!ctx) {
- fprintf(stderr, "failed to open store\n");
- return 1;
- }
-
- fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
- while (1) {
- unsigned percent = n * 100 / total;
- fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
- if (!split_msg(&all_msgs, &msg, &ofs))
- break;
- if (server.use_html)
- wrap_in_html(&msg);
- r = imap_store_msg(ctx, &msg);
- if (r != DRV_OK)
- break;
- n++;
- }
- fprintf(stderr, "\n");
+ if (server.tunnel)
+ return append_msgs_to_imap(&server, &all_msgs, total);
- imap_close_store(ctx);
+#ifdef USE_CURL_FOR_IMAP_SEND
+ if (use_curl)
+ return curl_append_msgs_to_imap(&server, &all_msgs, total);
+#endif
- return 0;
+ return append_msgs_to_imap(&server, &all_msgs, total);
}
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
- if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
+ if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
commit->object.flags |= SHOWN;
show_edge(commit);
}
}
mark_edge_parents_uninteresting(commit, revs, show_edge);
}
- if (revs->edge_hint) {
+ if (revs->edge_hint_aggressive) {
for (i = 0; i < revs->cmdline.nr; i++) {
struct object *obj = revs->cmdline.rev[i].item;
struct commit *commit = (struct commit *)obj;
path);
}
- strbuf_add(&lk->filename, path, pathlen);
- if (!(flags & LOCK_NO_DEREF))
- resolve_symlink(&lk->filename);
+ if (flags & LOCK_NO_DEREF) {
+ strbuf_add_absolute_path(&lk->filename, path);
+ } else {
+ struct strbuf resolved_path = STRBUF_INIT;
+
+ strbuf_add(&resolved_path, path, pathlen);
+ resolve_symlink(&resolved_path);
+ strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
+ strbuf_release(&resolved_path);
+ }
+
strbuf_addstr(&lk->filename, LOCK_SUFFIX);
lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
if (lk->fd < 0) {
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);
}
}
if (!ca) {
- ca = get_merge_bases(h1, h2, 1);
+ ca = get_merge_bases(h1, h2);
ca = reverse_commit_list(ca);
}
assert(local && remote);
/* Find merge bases */
- bases = get_merge_bases(local, remote, 1);
+ bases = get_merge_bases(local, remote);
if (!bases) {
base_sha1 = null_sha1;
base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
/* Prepare commit message and reflog message */
strbuf_addstr(&buf, msg);
- if (buf.buf[buf.len - 1] != '\n')
- strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
+ strbuf_complete_line(&buf);
create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
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 */
}
}
}
+
+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;
+ }
+}
}
}
+sub check_attr {
+ my ($attr,$path) = @_;
+ my $val = command_oneline("check-attr", $attr, "--", $path);
+ if ($val) { $val =~ s/^[^:]*:\s*[^:]*:\s*(.*)\s*$/$1/; }
+ return $val;
+}
+
+sub apply_manualprops {
+ my ($self, $file, $fbat) = @_;
+ my $pending_properties = check_attr( "svn-properties", $file );
+ if ($pending_properties eq "") { return; }
+ # Parse the list of properties to set.
+ my @props = split(/;/, $pending_properties);
+ # TODO: get existing properties to compare to
+ # - this fails for add so currently not done
+ # my $existing_props = ::get_svnprops($file);
+ my $existing_props = {};
+ # TODO: caching svn properties or storing them in .gitattributes
+ # would make that faster
+ foreach my $prop (@props) {
+ # Parse 'name=value' syntax and set the property.
+ if ($prop =~ /([^=]+)=(.*)/) {
+ my ($n,$v) = ($1,$2);
+ for ($n, $v) {
+ s/^\s+//; s/\s+$//;
+ }
+ my $existing = $existing_props->{$n};
+ if (!defined($existing) || $existing ne $v) {
+ $self->change_file_prop($fbat, $n, $v);
+ }
+ }
+ }
+}
+
sub A {
my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
undef, -1);
print "\tA\t$m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
$upa, $self->{r});
print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
$upa, $self->{r});
print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
my $fbat = $self->open_file($self->repo_path($m->{file_b}),
$pbat,$self->{r},$self->{pool});
print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q;
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
}
#define hex(a) (hexchar[(a) & 15])
-static char buffer[1000];
-static unsigned format_packet(const char *fmt, va_list args)
+static void format_packet(struct strbuf *out, const char *fmt, va_list args)
{
static char hexchar[] = "0123456789abcdef";
- unsigned n;
+ size_t orig_len, n;
- n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args);
- if (n >= sizeof(buffer)-4)
+ orig_len = out->len;
+ strbuf_addstr(out, "0000");
+ strbuf_vaddf(out, fmt, args);
+ n = out->len - orig_len;
+
+ if (n > LARGE_PACKET_MAX)
die("protocol error: impossibly long line");
- n += 4;
- buffer[0] = hex(n >> 12);
- buffer[1] = hex(n >> 8);
- buffer[2] = hex(n >> 4);
- buffer[3] = hex(n);
- packet_trace(buffer+4, n-4, 1);
- return n;
+
+ out->buf[orig_len + 0] = hex(n >> 12);
+ out->buf[orig_len + 1] = hex(n >> 8);
+ out->buf[orig_len + 2] = hex(n >> 4);
+ out->buf[orig_len + 3] = hex(n);
+ packet_trace(out->buf + orig_len + 4, n - 4, 1);
}
void packet_write(int fd, const char *fmt, ...)
{
+ static struct strbuf buf = STRBUF_INIT;
va_list args;
- unsigned n;
+ strbuf_reset(&buf);
va_start(args, fmt);
- n = format_packet(fmt, args);
+ format_packet(&buf, fmt, args);
va_end(args);
- write_or_die(fd, buffer, n);
+ write_or_die(fd, buf.buf, buf.len);
}
void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
{
va_list args;
- unsigned n;
va_start(args, fmt);
- n = format_packet(fmt, args);
+ format_packet(buf, fmt, args);
va_end(args);
- strbuf_add(buf, buffer, n);
}
static int get_packet_data(int fd, char **src_buf, size_t *src_size,
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')
* Return a pointer to the refname within the line (null-terminated),
* or NULL if there was a problem.
*/
-static const char *parse_ref_line(char *line, unsigned char *sha1)
+static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
{
+ const char *ref;
+
/*
* 42: the answer to everything.
*
* +1 (space in between hex and name)
* +1 (newline at the end of the line)
*/
- int len = strlen(line) - 42;
-
- if (len <= 0)
+ if (line->len <= 42)
return NULL;
- if (get_sha1_hex(line, sha1) < 0)
+
+ if (get_sha1_hex(line->buf, sha1) < 0)
return NULL;
- if (!isspace(line[40]))
+ if (!isspace(line->buf[40]))
return NULL;
- line += 41;
- if (isspace(*line))
+
+ ref = line->buf + 41;
+ if (isspace(*ref))
return NULL;
- if (line[len] != '\n')
+
+ if (line->buf[line->len - 1] != '\n')
return NULL;
- line[len] = 0;
+ line->buf[--line->len] = 0;
- return line;
+ return ref;
}
/*
static void read_packed_refs(FILE *f, struct ref_dir *dir)
{
struct ref_entry *last = NULL;
- char refline[PATH_MAX];
+ struct strbuf line = STRBUF_INIT;
enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
- while (fgets(refline, sizeof(refline), f)) {
+ while (strbuf_getwholeline(&line, f, '\n') != EOF) {
unsigned char sha1[20];
const char *refname;
- static const char header[] = "# pack-refs with:";
+ const char *traits;
- if (!strncmp(refline, header, sizeof(header)-1)) {
- const char *traits = refline + sizeof(header) - 1;
+ if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
if (strstr(traits, " fully-peeled "))
peeled = PEELED_FULLY;
else if (strstr(traits, " peeled "))
continue;
}
- refname = parse_ref_line(refline, sha1);
+ refname = parse_ref_line(&line, sha1);
if (refname) {
int flag = REF_ISPACKED;
continue;
}
if (last &&
- refline[0] == '^' &&
- strlen(refline) == PEELED_LINE_LENGTH &&
- refline[PEELED_LINE_LENGTH - 1] == '\n' &&
- !get_sha1_hex(refline + 1, sha1)) {
+ line.buf[0] == '^' &&
+ line.len == PEELED_LINE_LENGTH &&
+ line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
+ !get_sha1_hex(line.buf + 1, sha1)) {
hashcpy(last->u.value.peeled, sha1);
/*
* Regardless of what the file header said,
last->flag |= REF_KNOWS_PEELED;
}
}
+
+ strbuf_release(&line);
}
/*
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_release(&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);
}
/*
}
}
+static void set_merge(struct branch *ret)
+{
+ char *ref;
+ unsigned char sha1[20];
+ int i;
+
+ ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
+ for (i = 0; i < ret->merge_nr; i++) {
+ ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
+ ret->merge[i]->src = xstrdup(ret->merge_name[i]);
+ if (!remote_find_tracking(ret->remote, ret->merge[i]) ||
+ strcmp(ret->remote_name, "."))
+ continue;
+ if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]),
+ sha1, &ref) == 1)
+ ret->merge[i]->dst = ref;
+ else
+ ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
+ }
+}
+
struct branch *branch_get(const char *name)
{
struct branch *ret;
ret = make_branch(name, 0);
if (ret && ret->remote_name) {
ret->remote = remote_get(ret->remote_name);
- if (ret->merge_nr) {
- int i;
- ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
- for (i = 0; i < ret->merge_nr; i++) {
- ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
- ret->merge[i]->src = xstrdup(ret->merge_name[i]);
- if (remote_find_tracking(ret->remote, ret->merge[i])
- && !strcmp(ret->remote_name, "."))
- ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
- }
- }
+ if (ret->merge_nr)
+ set_merge(ret);
}
return ret;
}
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;
other = lookup_commit_or_die(sha1, "MERGE_HEAD");
add_pending_object(revs, &head->object, "HEAD");
add_pending_object(revs, &other->object, "MERGE_HEAD");
- bases = get_merge_bases(head, other, 1);
+ bases = get_merge_bases(head, other);
add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases);
: lookup_commit_reference(b_obj->sha1));
if (!a || !b)
goto missing;
- exclude = get_merge_bases(a, b, 1);
+ exclude = get_merge_bases(a, b);
add_rev_cmdline_list(revs, exclude,
REV_CMD_MERGE_BASE,
flags_exclude);
revs->tree_objects = 1;
revs->blob_objects = 1;
revs->edge_hint = 1;
+ } else if (!strcmp(arg, "--objects-edge-aggressive")) {
+ revs->tag_objects = 1;
+ revs->tree_objects = 1;
+ revs->blob_objects = 1;
+ revs->edge_hint = 1;
+ revs->edge_hint_aggressive = 1;
} else if (!strcmp(arg, "--verify-objects")) {
revs->tag_objects = 1;
revs->tree_objects = 1;
blob_objects:1,
verify_objects:1,
edge_hint:1,
+ edge_hint_aggressive:1,
limited:1,
unpacked:1,
boundary:2,
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
NULL,
NULL,
NULL,
+ NULL,
};
struct child_process po = CHILD_PROCESS_INIT;
int i;
argv[i++] = "-q";
if (args->progress)
argv[i++] = "--progress";
+ if (is_repository_shallow())
+ argv[i++] = "--shallow";
po.argv = argv;
po.in = -1;
po.out = args->stateless_rpc ? -1 : fd;
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
FILE *fp = NULL;
safe_create_leading_directories(path);
- fd = mkstemp(tmp);
+ fd = git_mkstemp_mode(tmp, 0666);
if (fd < 0)
goto out;
fp = fdopen(fd, "w");
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);
two = lookup_commit_reference_gently(sha1_tmp, 0);
if (!two)
return -1;
- mbs = get_merge_bases(one, two, 1);
+ mbs = get_merge_bases(one, two);
if (!mbs || mbs->next)
st = -1;
else {
const char *next = memchr(buf, '\n', size);
next = next ? (next + 1) : (buf + size);
- prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1;
+ prefix = ((prefix2 && (buf[0] == '\n' || buf[0] == '\t'))
+ ? prefix2 : prefix1);
strbuf_addstr(out, prefix);
strbuf_add(out, buf, next - buf);
size -= next - buf;
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);
left->object.flags |= SYMMETRIC_LEFT;
add_pending_object(rev, &left->object, path);
add_pending_object(rev, &right->object, path);
- merge_bases = get_merge_bases(left, right, 1);
+ merge_bases = get_merge_bases(left, right);
if (merge_bases) {
if (merge_bases->item == left)
*fast_forward = 1;
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
say "Your version of gpg (1.0.6) is too buggy for testing"
;;
*)
- # key generation info: gpg --homedir t/lib-gpg --gen-key
- # Type DSA and Elgamal, size 2048 bits, no expiration date.
- # Name and email: C O Mitter <committer@example.com>
+ # Available key info:
+ # * Type DSA and Elgamal, size 2048 bits, no expiration date,
+ # name and email: C O Mitter <committer@example.com>
+ # * Type RSA, size 2048 bits, no expiration date,
+ # name and email: Eris Discordia <discord@example.net>
# No password given, to enable non-interactive operation.
- cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome
- chmod 0700 gpghome
- chmod 0600 gpghome/*
- GNUPGHOME="$(pwd)/gpghome"
- export GNUPGHOME
+ # To generate new key:
+ # gpg --homedir /tmp/gpghome --gen-key
+ # To write armored exported key to keyring:
+ # gpg --homedir /tmp/gpghome --export-secret-keys \
+ # --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
+ # To export ownertrust:
+ # gpg --homedir /tmp/gpghome --export-ownertrust \
+ # > lib-gpg/ownertrust
+ mkdir ./gpghome &&
+ chmod 0700 ./gpghome &&
+ GNUPGHOME="$(pwd)/gpghome" &&
+ export GNUPGHOME &&
+ gpg --homedir "${GNUPGHOME}" 2>/dev/null --import \
+ "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
+ gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
+ "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
test_set_prereq GPG
;;
esac
fi
+if test_have_prereq GPG &&
+ echo | gpg --homedir "${GNUPGHOME}" -b --rfc1991 >/dev/null 2>&1
+then
+ test_set_prereq RFC1991
+fi
+
sanitize_pgp() {
perl -ne '
/^-----END PGP/ and $in_pgp = 0;
--- /dev/null
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQG7BEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD
+36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+
+PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj
+fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY
+8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL
+JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN
+NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh
+sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE
+yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/QAAn3TEzKR1pxxR
++R3dHuFpnnfatMIDC5O0IkMgTyBNaXR0ZXIgPGNvbW1pdHRlckBleGFtcGxlLmNv
+bT6IXgQTEQIAHgUCRmfLKQIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRATtvUe
+zd5DDXQdAKC92f+wOrTkbmPEf+u+qA/Gv6BxQwCfQ128JXCi3MpMB8tI2Kmo15tY
+gnmdAj0ERmfLThAIAM65eT9T6+gg0fJn+Qxhs3FFDPjxK6AOBS3SieWWmXO6stZZ
+plvb7r2+sXYp8HMHntnOX3TRPolIx1dsdkv3W3w8yUzf9Lmo2XMPsZ3/isWdEbOI
+A0rO3B1xwbQO7vEoWHeB7uyYIF6YsIH0pMqxkImciwB1tnJPB9OxqPHlD/HyyHr2
+voj6nmEGaPQWj8/dkfyenXm6XmNZUZL/slk6tRhNwv4cW3QQLh39nbiz9rqvZMKF
+XX8wkY4FdQkJjCGwqzG+7yJcyHvem29/iq//jRLZgdiN8BwV3MCTJyDp8/Wb/d9y
+jZcUm1RdtwRiwfhfQ+zmpyspm7OxINfH65rf7f8ABA0IALRiMRs/eOD59jrYXmPS
+ZQUbiALlbJJtuP2c9N3WZ5OgrhDiAW+SDIN+hgDynJ9b7C2dE3xNaud4zaXAAF44
+J4J0bAo2ZtZoJajw+GXwaZfh4Z7nPNHwEcbFD4/uXPCj9jPkcLOJqGmUY1aXdygo
+t3Hn5U/zo8JxPQ83YbJQhkzAOZ/HGowLNqKgGkLLHn1X9qay0CxlfTQeEN5RZyl3
+b4qRzGgGALFvoheyZIUw1TbjRpbn3kqlJooEQY02VwXFXfLI/LwzglilH6sSckvs
+0WHKLZ+0L6b3CgJHN2RsZ7QxwCBi1aemsvr65FeEXp/AYxaG5duUbsugG8PgoJ06
+bsEAAVQNQO3cXWpuiJ/nNLLnWuPunBKJUlurkBdf2GD+m+muF0VpwDchhqqbTO4e
+FqOISQQYEQIACQUCRmfLTgIbDAAKCRATtvUezd5DDcHsAKDQcoAtDWJFupVRqleB
+Cezx4Q2khACcCs+/LtE8Lb9hC+2cvr3uH5p82AI=
+=aEiU
+-----END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQOYBFFMlkcBCADJi/xnAF8yI34PHilSCbM7VtOFO17oFMkpu4cgN2QpPuM5MVjy
+cvrzKSguZFvPCDLzeAFJW1uPxL4SHaHSkisCrFhijH7OJWcOPNPSFCwu+inAoAsv
+Hm4ns6pfDZyRjVTHSY4rdMISqKFRozaXu8vHeBRzIhFnubBCepKZW07oKPnrnELV
+TVUSUVI+6el8JFmJIWxxLNLhfRRSPF0v4MDXPF//iCWiZDI+J1pLvQ5V/f7YtfsD
+GV0oPY66J72BFJG555eKBttnNY901LmI3ocn5P5iVnXDaqMElw7FKpnANXucgY3H
+4kLyNkI3s3J0CGbXI7b3MBWtjctuhWv1q2G5ABEBAAEAB/wLiuza/qEfv1Cfj7FQ
+ytAXpz1YoAcrcM/53TeRQhrbvIee5ZNGhLdCkyot81QeuJrSaXO0E9CxRynrjQQ7
+ibYqN7Hy0uu1kAbQQJjmVdQXTKnKJ7Wm7oM4hYhNsVCKNXc+1+5AfDYGg4nZob36
+qqgHtc+Ardl5VfUg7uF+eZrnSMynjZANgikKbPtE09DKVtVOtUE4xTD9ijkpgn65
+glsZDqb7J4QVgTeEiCDKJsQvin3SwrPBqBxBRULF2TIaMbOwe6dHiiaI85rsvAWS
+VGzonUB3IU1470P2SDIVczbXYUK/nDSGx6ZZ0wLu9ZcCyUPvxVEykuh2P4UWHla+
+nHLRBADMLavcfjsCI5CRUsdurYpgE8Y3bEbcDpvzAu5jT5D25p3YPDODOXD3AKTt
+PzVMARVtv8twkbgAyWaoDevJz8OtmoSwsWjdFo4YvsYw9jV7Yf3GwzD3Ya1ZnW32
+JWQr6cX8qcK0AukAD7UZkVyhU2KBvB02t8lKHLbScHXTYVqrywQA/LNUXwmHji+6
+osnSQAC8X9ggMOEs9dGo7Qlk4JgfGAH17CFI3S3ubsaVEdxz3YwzOkD8SNmEbLyW
+a7CZ/RnpdAZU0nB7kSfbfZl7ajhPbgKBMsaV2yvaDdJeor4m5eKdXffRk0SksxjL
+Z/4P1tTIuL8WzetGB/aDcWDFgseSAAsEALzmf579ptlSmDyGRAKQqub+mj4V3EUZ
+1GVGcfBY86w3BZVDsaRiCtcNjk/lcP4AZ1Vbb42RM6jk8nLsENRc7rf2xa7ZPf0T
+6n5F6W+vk7EG76RoFhKVtGZngGKiDGVavxk3FT/yf8lKrT3wYiT03SZDuZ0pWvku
+FiJGEyesAC8WRz60JEVyaXMgRGlzY29yZGlhIDxkaXNjb3JkQGV4YW1wbGUubmV0
+PokBOAQTAQIAIgUCUUyWRwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ
+YQkuhbcicYlYowf7B+f+FDcLVfw8XzGlKku1F6PI1yGCt7AMO2/JkmO4LlgHuIgF
+pqe5b/XjKl0IsRcbVLitqiIokc8u+7H8yYU67DDliq7t1gqBy+qThSHcgn6WMKTa
+qCqOE2jzHyqulIAzQsJQ+c5SRofEZAKT4Qa2Dy+nsqWDpIE78aJd0Vnkk9U6H2Vu
+ABvUeN/IMgvxPr525o+rBD7LU4J3CtOzfV+sO6+33da+Bm9UhkR4tC4H/n1dDN1J
+YuxBQbgxTq/h8mKe4/7/Yvy+5WsYd96ZRLE2ZFWeWXtKkwmYbQ42G3SZUXaZ8R8O
+tbTyUrjbFKipO4wvXwhyju1l9cxAsrca6xbSCJ0DmARRTJZHAQgAqTtPFcTXqM+U
+o7bOoo+dcHi8XDf/8XSEmZfMKc/U5pSTBk7h1gSKuGzjF2n3wQm6A8+101vTLaQ6
+PoFDFW8uQB00mjymGrRDYFgz8bjhnaekZnA4XThr1ROjffgMhs3uTpCebdV+lL8K
+0oJTHc39TPLTg23DFcRSDN+3ARJJS7+CRBIbt9L5gObpgA4HUap/o6N7O04rQOPU
+83MAqnwo2JTO/Ded0zoad0Vo31Nmk4F+KvEE52ftGHbd7yqIUGKBt2SeTAh850ac
+LeNZP+V1Y7atBCr7/zm+JpHWq9OH7/NomlEIkxL8WDt8GfAKoqZgqefL+ACEnLbA
+t1du3f0FswARAQABAAf8DclaIQDfPM5kYo3y+YVPoykC11RskmQWpVibdlCLHJm/
+/ISSm1fVYT7lpTOpzl0XfVX/jw9s/cviPtNS/r0G/Iwki+gi9Av5bTDiUm/oWWqd
+1waPYPDGwB4QdKOviY/fOSFI9tOsszt5Czs4wDXWy90AZDWd7fkHYisbgofV1sjK
+Q8bYQPabcepcZ2JyET+EpZBEmUHHqQ76bTiqjN+Vz6k1OFlsEBzGkE+WIakAhkQ2
+57oUrRgFe+h6Ch7meB/v6vVfIRSsLpZe183uc4SigqtfsgjbG9PqOcAJOqovDncB
+Scg3qvpWFOAkTA3Re+yBPUd2HHl9WF/TPa2kBDCT2QQAxcJZeUCuUgDgCizqEgfs
+Kzm6dy4G/OJdW0q9m9psHqD1XWLd7ZLE4+eTS1cxktJiGcGNdGoZD0EtgxkV09uM
+12QYCOBErFJzv4/4oledHeEhTaRR/mFFGRp+kWTz2Ai/zNqUd3D++DYUe8g4mVQJ
+6JP014XhvoRnaCfT8cH9Zd0EANsSL70WGdifcVoWKA9jFJhahc0sSG6IZvMOc7bs
+cSbhBqLEnheObkarBP+A+zgllqIf+sbCassMXjcV52mnl9th3J5RWr7scrQLJ9ZX
+Ivz3uoP85vwlUI98dI9roYK0OpKmG4hNFppAcgiCVNVjnQlhuQ/HoexRHxRmnmcb
+38jPA/sEHPCFbLCGOSB+HQNKx/5Wf6VpFX/4oBNbIUiYoxcRl0jpYT7Lc0zbc8So
+HthjPfWhXhKzYvEDC5YgASEy1cNbGMUJcGyuAInwIQjq44FSwRMkI3ISSHnbv1iH
+0wBVJUzpluMebEAesdZUz1DcZWVf6eVJD0dhZxD6DoG7Xj1m9ThUiQEfBBgBAgAJ
+BQJRTJZHAhsMAAoJEGEJLoW3InGJ7HEIAMXkMf4cOWmnAuvvcSm3KpLghuWik9dy
+fn1sY/IG5atoKK+ypmV/TlBlMZqFQzuPIJQT8VLbmxtLlDhJG04LbI6c8axIZxOO
+ZKLy5nTTSy16ztqEeS7eifHLPZg1UFFyEEIQ1XW0CNDAeuWKh90ERjyl4Cg7PnWS
+Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk
+4UTkXbg9pn3umCgkNJ3Vs8fWnIWO9Izdr2/wrFY2JvUT7Yvl+wsNIWatvOEzGy7n
+BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ=
+=hieJ
+-----END PGP PRIVATE KEY BLOCK-----
--- /dev/null
+# List of assigned trustvalues, created Thu 11 Dec 2014 01:26:28 PM CET
+# (Use "gpg --import-ownertrust" to restore them)
+73D758744BE721698EC54E8713B6F51ECDDE430D:6:
+D4BE22311AD3131E5EDA29A461092E85B7227189:3:
PassEnv GIT_VALGRIND
PassEnv GIT_VALGRIND_OPTIONS
PassEnv GNUPGHOME
+PassEnv ASAN_OPTIONS
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
check_approxidate '5AM Jun 6' '2009-06-06 05:00:00'
check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'
+check_approxidate '2008-12-01' '2008-12-01 19:20:00'
+check_approxidate '2009-12-01' '2009-12-01 19:20:00'
+
test_done
esac
}
+check_warning () {
+ case "$1" in
+ LF_CRLF) grep "LF will be replaced by CRLF" $2;;
+ CRLF_LF) grep "CRLF will be replaced by LF" $2;;
+ '')
+ >expect
+ grep "will be replaced by" $2 >actual
+ test_cmp expect actual
+ ;;
+ *) false ;;
+ esac
+}
+
create_file_in_repo () {
crlf=$1
attr=$2
+ lfname=$3
+ crlfname=$4
+ lfmixcrlf=$5
+ lfmixcr=$6
+ crlfnul=$7
create_gitattributes "$attr" &&
+ pfx=crlf_${crlf}_attr_${attr}
for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
do
- pfx=crlf_${crlf}_attr_${attr}_$f.txt &&
- cp $f $pfx && git -c core.autocrlf=$crlf add $pfx
+ fname=${pfx}_$f.txt &&
+ cp $f $fname &&
+ git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
done &&
- git commit -m "core.autocrlf $crlf"
+ git commit -m "core.autocrlf $crlf" &&
+ check_warning "$lfname" ${pfx}_LF.err &&
+ check_warning "$crlfname" ${pfx}_CRLF.err &&
+ check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err &&
+ check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err &&
+ check_warning "$crlfnul" ${pfx}_CRLF_nul.err
}
check_files_in_repo () {
'
-test_expect_success 'create files' '
- create_file_in_repo false "" &&
- create_file_in_repo true "" &&
- create_file_in_repo input "" &&
- create_file_in_repo false "auto" &&
- create_file_in_repo true "auto" &&
- create_file_in_repo input "auto" &&
+warn_LF_CRLF="LF will be replaced by CRLF"
+warn_CRLF_LF="CRLF will be replaced by LF"
+
+test_expect_success 'add files empty attr' '
+ create_file_in_repo false "" "" "" "" "" "" &&
+ create_file_in_repo true "" "LF_CRLF" "" "LF_CRLF" "" "" &&
+ create_file_in_repo input "" "" "CRLF_LF" "CRLF_LF" "" ""
+'
+
+test_expect_success 'add files attr=auto' '
+ create_file_in_repo false "auto" "" "CRLF_LF" "CRLF_LF" "" "" &&
+ create_file_in_repo true "auto" "LF_CRLF" "" "LF_CRLF" "" "" &&
+ create_file_in_repo input "auto" "" "CRLF_LF" "CRLF_LF" "" ""
+'
+
+test_expect_success 'add files attr=text' '
+ create_file_in_repo false "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" &&
+ create_file_in_repo true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" &&
+ create_file_in_repo input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF"
+'
+
+test_expect_success 'add files attr=-text' '
+ create_file_in_repo false "-text" "" "" "" "" "" &&
+ create_file_in_repo true "-text" "" "" "" "" "" &&
+ create_file_in_repo input "-text" "" "" "" "" ""
+'
+
+test_expect_success 'add files attr=lf' '
+ create_file_in_repo false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" &&
+ create_file_in_repo true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" &&
+ create_file_in_repo input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF"
+'
- create_file_in_repo false "text" &&
- create_file_in_repo true "text" &&
- create_file_in_repo input "text" &&
+test_expect_success 'add files attr=crlf' '
+ create_file_in_repo false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" &&
+ create_file_in_repo true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" &&
+ create_file_in_repo input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" ""
+'
- create_file_in_repo false "-text" &&
- create_file_in_repo true "-text" &&
- create_file_in_repo input "-text" &&
+test_expect_success 'create files cleanup' '
rm -f *.txt &&
git reset --hard
'
test_cmp expect actual
'
+test_expect_success 'avoid SP-HT sequence in commented line' '
+ printf "#\tone\n#\n# two\n" >expect &&
+ printf "\tone\n\ntwo\n" | git stripspace -c >actual &&
+ test_cmp expect actual
+'
+
test_done
git checkout -f master
'
-$test_case 'rename (case change)' '
+test_expect_success 'rename (case change)' '
git mv camelcase CamelCase &&
git commit -m "rename"
'
# ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux
# We want to count only foo because it's the only direct child
subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) &&
- subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 {++c} END {print c}') &&
+ subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 != "" {++c} END {print c}') &&
entries=$(git ls-files|wc -l) &&
printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" &&
for subtree in $subtrees
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
done
+test_expect_success POSIXPERM 'info/refs respects umask in unshared repo' '
+ rm -f .git/info/refs &&
+ test_unconfig core.sharedrepository &&
+ umask 002 &&
+ git update-server-info &&
+ echo "-rw-rw-r--" >expect &&
+ modebits .git/info/refs >actual &&
+ test_cmp expect actual
+'
+
test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
+ umask 077 &&
git config core.sharedRepository group &&
git reflog expire --all &&
actual="$(ls -l .git/logs/refs/heads/master)" &&
test_must_fail git rev-parse --verify -q $c
'
+test_expect_success 'stdin verify succeeds for correct value' '
+ git rev-parse $m >expect &&
+ echo "verify $m $m" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin verify succeeds for missing reference' '
+ echo "verify refs/heads/missing $Z" >stdin &&
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin verify treats no value as missing' '
+ echo "verify refs/heads/missing" >stdin &&
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin verify fails for wrong value' '
+ git rev-parse $m >expect &&
+ echo "verify $m $m~1" >stdin &&
+ test_must_fail git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin verify fails for mistaken null value' '
+ git rev-parse $m >expect &&
+ echo "verify $m $Z" >stdin &&
+ test_must_fail git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin verify fails for mistaken empty value' '
+ M=$(git rev-parse $m) &&
+ test_when_finished "git update-ref $m $M" &&
+ git rev-parse $m >expect &&
+ echo "verify $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'stdin update refs works with identity updates' '
cat >stdin <<-EOF &&
update $a $m $m
test_must_fail git rev-parse --verify -q $c
'
+test_expect_success 'stdin -z verify succeeds for correct value' '
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "$m" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify succeeds for missing reference' '
+ printf $F "verify refs/heads/missing" "$Z" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin -z verify treats no value as missing' '
+ printf $F "verify refs/heads/missing" "" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin -z verify fails for wrong value' '
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "$m~1" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify fails for mistaken null value' '
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "$Z" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify fails for mistaken empty value' '
+ M=$(git rev-parse $m) &&
+ test_when_finished "git update-ref $m $M" &&
+ git rev-parse $m >expect &&
+ printf $F "verify $m" "" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin &&
+ git rev-parse $m >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'stdin -z update refs works with identity updates' '
printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin &&
git update-ref -z --stdin <stdin &&
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
echo $tag >.git/refs/tags/wrong &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
git fsck --tags 2>out &&
- grep "invalid .tag. name" out &&
- grep "expected .tagger. line" out
+
+ cat >expect <<-EOF &&
+ warning in tag $tag: invalid '\''tag'\'' name: wrong name format
+ warning in tag $tag: invalid format - expected '\''tagger'\'' line
+ EOF
+ test_cmp expect out
'
test_expect_success 'tag with bad tagger' '
)
'
-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' '
+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
+
+test_expect_success 'fsck allows .Ňit' '
(
- 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
+ git init not-dotgit &&
+ cd not-dotgit &&
+ echo content >file &&
+ git add file &&
+ git commit -m base &&
+ blob=$(git rev-parse :file) &&
+ printf "100644 blob $blob\t.\\305\\207it" >tree &&
+ tree=$(git mktree <tree) &&
+ git fsck 2>err &&
+ test_line_count = 0 err
)
'
. ./test-lib.sh
-test_expect_success \
-'preparation' '
-mkdir asubdir &&
-echo tree1path0 >path0 &&
-echo tree1path1 >path1 &&
-echo tree1path3 >path3 &&
-echo tree1path4 >path4 &&
-echo tree1asubdir/path5 >asubdir/path5 &&
-git update-index --add path0 path1 path3 path4 asubdir/path5 &&
-t1=$(git write-tree) &&
-rm -f path* .merge_* out .git/index &&
-echo tree2path0 >path0 &&
-echo tree2path1 >path1 &&
-echo tree2path2 >path2 &&
-echo tree2path4 >path4 &&
-git update-index --add path0 path1 path2 path4 &&
-t2=$(git write-tree) &&
-rm -f path* .merge_* out .git/index &&
-echo tree2path0 >path0 &&
-echo tree3path1 >path1 &&
-echo tree3path2 >path2 &&
-echo tree3path3 >path3 &&
-git update-index --add path0 path1 path2 path3 &&
-t3=$(git write-tree)'
-
-test_expect_success \
-'checkout one stage 0 to temporary file' '
-rm -f path* .merge_* out .git/index &&
-git read-tree $t1 &&
-git checkout-index --temp -- path1 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path1 &&
-p=$(cut "-d " -f1 out) &&
-test -f $p &&
-test $(cat $p) = tree1path1'
-
-test_expect_success \
-'checkout all stage 0 to temporary files' '
-rm -f path* .merge_* out .git/index &&
-git read-tree $t1 &&
-git checkout-index -a --temp >out &&
-test_line_count = 5 out &&
-for f in path0 path1 path3 path4 asubdir/path5
-do
- test $(grep $f out | cut "-d " -f2) = $f &&
- p=$(grep $f out | cut "-d " -f1) &&
+test_expect_success 'setup' '
+ mkdir asubdir &&
+ echo tree1path0 >path0 &&
+ echo tree1path1 >path1 &&
+ echo tree1path3 >path3 &&
+ echo tree1path4 >path4 &&
+ echo tree1asubdir/path5 >asubdir/path5 &&
+ git update-index --add path0 path1 path3 path4 asubdir/path5 &&
+ t1=$(git write-tree) &&
+ rm -f path* .merge_* actual .git/index &&
+ echo tree2path0 >path0 &&
+ echo tree2path1 >path1 &&
+ echo tree2path2 >path2 &&
+ echo tree2path4 >path4 &&
+ git update-index --add path0 path1 path2 path4 &&
+ t2=$(git write-tree) &&
+ rm -f path* .merge_* actual .git/index &&
+ echo tree2path0 >path0 &&
+ echo tree3path1 >path1 &&
+ echo tree3path2 >path2 &&
+ echo tree3path3 >path3 &&
+ git update-index --add path0 path1 path2 path3 &&
+ t3=$(git write-tree)
+'
+
+test_expect_success 'checkout one stage 0 to temporary file' '
+ rm -f path* .merge_* actual .git/index &&
+ git read-tree $t1 &&
+ git checkout-index --temp -- path1 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path1 &&
+ p=$(cut "-d " -f1 actual) &&
test -f $p &&
- test $(cat $p) = tree1$f
-done'
-
-test_expect_success \
-'prepare 3-way merge' '
-rm -f path* .merge_* out .git/index &&
-git read-tree -m $t1 $t2 $t3'
-
-test_expect_success \
-'checkout one stage 2 to temporary file' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=2 --temp -- path1 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path1 &&
-p=$(cut "-d " -f1 out) &&
-test -f $p &&
-test $(cat $p) = tree2path1'
-
-test_expect_success \
-'checkout all stage 2 to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index --all --stage=2 --temp >out &&
-test_line_count = 3 out &&
-for f in path1 path2 path4
-do
- test $(grep $f out | cut "-d " -f2) = $f &&
- p=$(grep $f out | cut "-d " -f1) &&
+ test $(cat $p) = tree1path1
+'
+
+test_expect_success 'checkout all stage 0 to temporary files' '
+ rm -f path* .merge_* actual .git/index &&
+ git read-tree $t1 &&
+ git checkout-index -a --temp >actual &&
+ test_line_count = 5 actual &&
+ for f in path0 path1 path3 path4 asubdir/path5
+ do
+ test $(grep $f actual | cut "-d " -f2) = $f &&
+ p=$(grep $f actual | cut "-d " -f1) &&
+ test -f $p &&
+ test $(cat $p) = tree1$f
+ done
+'
+
+test_expect_success 'setup 3-way merge' '
+ rm -f path* .merge_* actual .git/index &&
+ git read-tree -m $t1 $t2 $t3
+'
+
+test_expect_success 'checkout one stage 2 to temporary file' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=2 --temp -- path1 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path1 &&
+ p=$(cut "-d " -f1 actual) &&
test -f $p &&
- test $(cat $p) = tree2$f
-done'
-
-test_expect_success \
-'checkout all stages/one file to nothing' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=all --temp -- path0 >out &&
-test_line_count = 0 out'
-
-test_expect_success \
-'checkout all stages/one file to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=all --temp -- path1 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path1 &&
-cut "-d " -f1 out | (read s1 s2 s3 &&
-test -f $s1 &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s1) = tree1path1 &&
-test $(cat $s2) = tree2path1 &&
-test $(cat $s3) = tree3path1)'
-
-test_expect_success \
-'checkout some stages/one file to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index --stage=all --temp -- path2 >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = path2 &&
-cut "-d " -f1 out | (read s1 s2 s3 &&
-test $s1 = . &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s2) = tree2path2 &&
-test $(cat $s3) = tree3path2)'
-
-test_expect_success \
-'checkout all stages/all files to temporary files' '
-rm -f path* .merge_* out &&
-git checkout-index -a --stage=all --temp >out &&
-test_line_count = 5 out'
-
-test_expect_success \
-'-- path0: no entry' '
-test x$(grep path0 out | cut "-d " -f2) = x'
-
-test_expect_success \
-'-- path1: all 3 stages' '
-test $(grep path1 out | cut "-d " -f2) = path1 &&
-grep path1 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s1) = tree1path1 &&
-test $(cat $s2) = tree2path1 &&
-test $(cat $s3) = tree3path1)'
-
-test_expect_success \
-'-- path2: no stage 1, have stage 2 and 3' '
-test $(grep path2 out | cut "-d " -f2) = path2 &&
-grep path2 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test $s1 = . &&
-test -f $s2 &&
-test -f $s3 &&
-test $(cat $s2) = tree2path2 &&
-test $(cat $s3) = tree3path2)'
-
-test_expect_success \
-'-- path3: no stage 2, have stage 1 and 3' '
-test $(grep path3 out | cut "-d " -f2) = path3 &&
-grep path3 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test $s2 = . &&
-test -f $s3 &&
-test $(cat $s1) = tree1path3 &&
-test $(cat $s3) = tree3path3)'
-
-test_expect_success \
-'-- path4: no stage 3, have stage 1 and 3' '
-test $(grep path4 out | cut "-d " -f2) = path4 &&
-grep path4 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test -f $s2 &&
-test $s3 = . &&
-test $(cat $s1) = tree1path4 &&
-test $(cat $s2) = tree2path4)'
-
-test_expect_success \
-'-- asubdir/path5: no stage 2 and 3 have stage 1' '
-test $(grep asubdir/path5 out | cut "-d " -f2) = asubdir/path5 &&
-grep asubdir/path5 out | cut "-d " -f1 | (read s1 s2 s3 &&
-test -f $s1 &&
-test $s2 = . &&
-test $s3 = . &&
-test $(cat $s1) = tree1asubdir/path5)'
-
-test_expect_success \
-'checkout --temp within subdir' '
-(cd asubdir &&
- git checkout-index -a --stage=all >out &&
- test_line_count = 1 out &&
- test $(grep path5 out | cut "-d " -f2) = path5 &&
- grep path5 out | cut "-d " -f1 | (read s1 s2 s3 &&
- test -f ../$s1 &&
- test $s2 = . &&
- test $s3 = . &&
- test $(cat ../$s1) = tree1asubdir/path5)
-)'
-
-test_expect_success \
-'checkout --temp symlink' '
-rm -f path* .merge_* out .git/index &&
-test_ln_s_add b a &&
-t4=$(git write-tree) &&
-rm -f .git/index &&
-git read-tree $t4 &&
-git checkout-index --temp -a >out &&
-test_line_count = 1 out &&
-test $(cut "-d " -f2 out) = a &&
-p=$(cut "-d " -f1 out) &&
-test -f $p &&
-test $(cat $p) = b'
+ test $(cat $p) = tree2path1
+'
+
+test_expect_success 'checkout all stage 2 to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --all --stage=2 --temp >actual &&
+ test_line_count = 3 actual &&
+ for f in path1 path2 path4
+ do
+ test $(grep $f actual | cut "-d " -f2) = $f &&
+ p=$(grep $f actual | cut "-d " -f1) &&
+ test -f $p &&
+ test $(cat $p) = tree2$f
+ done
+'
+
+test_expect_success 'checkout all stages/one file to nothing' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --temp -- path0 >actual &&
+ test_line_count = 0 actual
+'
+
+test_expect_success 'checkout all stages/one file to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --temp -- path1 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path1 &&
+ cut "-d " -f1 actual | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s1) = tree1path1 &&
+ test $(cat $s2) = tree2path1 &&
+ test $(cat $s3) = tree3path1)
+'
+
+test_expect_success 'checkout some stages/one file to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --temp -- path2 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path2 &&
+ cut "-d " -f1 actual | (read s1 s2 s3 &&
+ test $s1 = . &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s2) = tree2path2 &&
+ test $(cat $s3) = tree3path2)
+'
+
+test_expect_success 'checkout all stages/all files to temporary files' '
+ rm -f path* .merge_* actual &&
+ git checkout-index -a --stage=all --temp >actual &&
+ test_line_count = 5 actual
+'
+
+test_expect_success '-- path0: no entry' '
+ test x$(grep path0 actual | cut "-d " -f2) = x
+'
+
+test_expect_success '-- path1: all 3 stages' '
+ test $(grep path1 actual | cut "-d " -f2) = path1 &&
+ grep path1 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s1) = tree1path1 &&
+ test $(cat $s2) = tree2path1 &&
+ test $(cat $s3) = tree3path1)
+'
+
+test_expect_success '-- path2: no stage 1, have stage 2 and 3' '
+ test $(grep path2 actual | cut "-d " -f2) = path2 &&
+ grep path2 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test $s1 = . &&
+ test -f $s2 &&
+ test -f $s3 &&
+ test $(cat $s2) = tree2path2 &&
+ test $(cat $s3) = tree3path2)
+'
+
+test_expect_success '-- path3: no stage 2, have stage 1 and 3' '
+ test $(grep path3 actual | cut "-d " -f2) = path3 &&
+ grep path3 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test $s2 = . &&
+ test -f $s3 &&
+ test $(cat $s1) = tree1path3 &&
+ test $(cat $s3) = tree3path3)
+'
+
+test_expect_success '-- path4: no stage 3, have stage 1 and 3' '
+ test $(grep path4 actual | cut "-d " -f2) = path4 &&
+ grep path4 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test -f $s2 &&
+ test $s3 = . &&
+ test $(cat $s1) = tree1path4 &&
+ test $(cat $s2) = tree2path4)
+'
+
+test_expect_success '-- asubdir/path5: no stage 2 and 3 have stage 1' '
+ test $(grep asubdir/path5 actual | cut "-d " -f2) = asubdir/path5 &&
+ grep asubdir/path5 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f $s1 &&
+ test $s2 = . &&
+ test $s3 = . &&
+ test $(cat $s1) = tree1asubdir/path5)
+'
+
+test_expect_success 'checkout --temp within subdir' '
+ (
+ cd asubdir &&
+ git checkout-index -a --stage=all >actual &&
+ test_line_count = 1 actual &&
+ test $(grep path5 actual | cut "-d " -f2) = path5 &&
+ grep path5 actual | cut "-d " -f1 | (read s1 s2 s3 &&
+ test -f ../$s1 &&
+ test $s2 = . &&
+ test $s3 = . &&
+ test $(cat ../$s1) = tree1asubdir/path5)
+ )
+'
+
+test_expect_success 'checkout --temp symlink' '
+ rm -f path* .merge_* actual .git/index &&
+ test_ln_s_add path7 path6 &&
+ git checkout-index --temp -a >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = path6 &&
+ p=$(cut "-d " -f1 actual) &&
+ test -f $p &&
+ test $(cat $p) = path7
+'
+
+test_expect_success 'emit well-formed relative path' '
+ rm -f path* .merge_* actual .git/index &&
+ >path0123456789 &&
+ git update-index --add path0123456789 &&
+ (
+ cd asubdir &&
+ git checkout-index --temp -- ../path0123456789 >actual &&
+ test_line_count = 1 actual &&
+ test $(cut "-d " -f2 actual) = ../path0123456789
+ )
+'
test_done
test_branch_upstream spam repo_c spam
'
+test_expect_success 'loosely defined local base branch is reported correctly' '
+
+ git checkout master &&
+ git branch strict &&
+ git branch loose &&
+ git commit --allow-empty -m "a bit more" &&
+
+ test_config branch.strict.remote . &&
+ test_config branch.loose.remote . &&
+ test_config branch.strict.merge refs/heads/master &&
+ test_config branch.loose.merge master &&
+
+ git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
+ git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
+
+ test_cmp expect actual
+'
+
test_done
test_cmp expect actual
'
+test_expect_success '.lock files cleaned up' '
+ mkdir cleanup &&
+ (
+ cd cleanup &&
+ mkdir worktree &&
+ git init repo &&
+ cd repo &&
+ git config core.worktree ../../worktree &&
+ # --refresh triggers late setup_work_tree,
+ # active_cache_changed is zero, rollback_lock_file fails
+ git update-index --refresh &&
+ ! test -f .git/index.lock
+ )
+'
+
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_must_fail git branch -m o/o o
'
+test_expect_success 'git branch -m o/q o/p should fail when o/p exists' '
+ git branch o/q &&
+ test_must_fail git branch -m o/q o/p
+'
+
+test_expect_success 'git branch -M o/q o/p should work when o/p exists' '
+ git branch -M o/q o/p
+'
+
+test_expect_success 'git branch -m -f o/q o/p should work when o/p exists' '
+ git branch o/q &&
+ git branch -m -f o/q o/p
+'
+
test_expect_success 'git branch -m q r/q should fail when r exists' '
git branch q &&
git branch r &&
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'
'git diff-index -B -M "$tree" >current'
# file0 changed from regular to symlink. file1 is very close to the preimage of file0.
-# because we break file0, file1 can become a rename of it.
+# the change does not make file0 disappear, so file1 is denoted as a copy of file0
cat >expected <<\EOF
:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 C file0 file1
EOF
test_expect_success \
git diff-tree three four -r --name-status -B -M | sort >actual &&
{
- echo "R100 foo bar"
+ # see -B -M (#6) in t4008
+ echo "C100 foo bar"
echo "T100 foo"
} | sort >expect &&
test_cmp expect actual
color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m"
'
+# note that nobold and nodim are the same code (22)
+test_expect_success 'attr negation' '
+ color "nobold nodim noul noblink noreverse" "[22;24;25;27m"
+'
+
test_expect_success 'long color specification' '
color "254 255 bold dim ul blink reverse" "[1;2;4;5;7;38;5;254;48;5;255m"
'
+test_expect_success 'absurdly long color specification' '
+ color \
+ "#ffffff #ffffff bold nobold dim nodim ul noul blink noblink reverse noreverse" \
+ "[1;2;4;5;7;22;24;25;27;38;2;255;255;255;48;2;255;255;255m"
+'
+
test_expect_success '256 colors' '
color "254 bold 255" "[1;38;5;254;48;5;255m"
'
+test_expect_success '24-bit colors' '
+ color "#ff00ff black" "[38;2;255;0;255;40m"
+'
+
test_expect_success '"normal" yields no color at all"' '
color "normal black" "[40m"
'
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 "$victim_head" = "$pushed_head"
'
-test_expect_success \
- 'push can be used to delete a ref' '
+test_expect_success 'push can be used to delete a ref' '
( cd victim && git branch extra master ) &&
git send-pack ./victim :extra master &&
( cd victim &&
)
}
-rewound_push_succeeded() {
- cmp ../parent/.git/refs/heads/master .git/refs/heads/master
-}
-
-rewound_push_failed() {
- if rewound_push_succeeded
- then
- false
- else
- true
- fi
-}
-
test_expect_success 'pushing explicit refspecs respects forcing' '
rewound_push_setup &&
parent_orig=$(cd parent && git rev-parse --verify master) &&
# prune takes any number of args
# update takes any number of args
+test_expect_success 'add remote matching the "insteadOf" URL' '
+ git config url.xyz@example.com.insteadOf backup &&
+ git remote add backup xyz@example.com
+'
+
test_done
)
'
+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
test_cmp expect actual
'
+test_expect_success 'try to create repo with absurdly long refname' '
+ ref240=$_z40/$_z40/$_z40/$_z40/$_z40/$_z40 &&
+ ref1440=$ref240/$ref240/$ref240/$ref240/$ref240/$ref240 &&
+ git init long &&
+ (
+ cd long &&
+ test_commit long &&
+ test_commit master
+ ) &&
+ if git -C long update-ref refs/heads/$ref1440 long; then
+ test_set_prereq LONG_REF
+ else
+ echo >&2 "long refs not supported"
+ fi
+'
+
+test_expect_success LONG_REF 'fetch handles extremely long refname' '
+ git fetch long refs/heads/*:refs/remotes/long/* &&
+ cat >expect <<-\EOF &&
+ long
+ master
+ EOF
+ git for-each-ref --format="%(subject)" refs/remotes/long >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success LONG_REF 'push handles extremely long refname' '
+ git push long :refs/heads/$ref1440 &&
+ git -C long for-each-ref --format="%(subject)" refs/heads >actual &&
+ echo master >expect &&
+ test_cmp expect actual
+'
+
test_done
test_cmp expected "$base_dir/O/.git/objects/info/alternates"
'
+test_expect_success 'clone and dissociate from reference' '
+ git init P &&
+ (
+ cd P && test_commit one
+ ) &&
+ git clone P Q &&
+ (
+ cd Q && test_commit two
+ ) &&
+ git clone --no-local --reference=P Q R &&
+ git clone --no-local --reference=P --dissociate Q S &&
+ # removing the reference P would corrupt R but not S
+ rm -fr P &&
+ test_must_fail git -C R fsck &&
+ git -C S fsck
+'
+
test_done
git bisect reset
'
+test_expect_success '"git bisect bad HEAD" behaves as "git bisect bad"' '
+ git checkout parallel &&
+ git bisect start HEAD $HASH1 &&
+ git bisect good HEAD &&
+ git bisect bad HEAD &&
+ test "$HASH6" = $(git rev-parse --verify HEAD) &&
+ git bisect reset
+'
+
test_done
test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null
'
+test_expect_success 'Check that :track[short] works when upstream is invalid' '
+ cat >expected <<-\EOF &&
+
+
+ EOF
+ test_when_finished "git config branch.master.merge refs/heads/master" &&
+ git config branch.master.merge refs/heads/does-not-exist &&
+ git for-each-ref \
+ --format="%(upstream:track)$LF%(upstream:trackshort)" \
+ refs/heads >actual &&
+ test_cmp expected actual
+'
+
cat >expected <<EOF
$(git rev-parse --short HEAD)
EOF
get_tag_header rfc1991-signed-tag $commit commit $time >expect
echo "RFC1991 signed tag" >>expect
echo '-----BEGIN PGP MESSAGE-----' >>expect
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'creating a signed tag with rfc1991' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
EOF
chmod +x fakeeditor
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'reediting a signed tag body omits signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "RFC1991 signed tag" >expect &&
test_cmp expect actual
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'verifying rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'list tag with rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
rm -f gpghome/gpg.conf
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'verifying rfc1991 signature without --rfc1991' '
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'list tag with rfc1991 signature without --rfc1991' '
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
test_cmp expect actual
'
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
'reediting a signed tag body omits signature' '
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
'
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 &&
# May be altered later in the test
PREREQ="PERL"
-test_expect_success $PREREQ \
- 'prepare reference tree' \
- 'echo "1A quick brown fox jumps over the" >file &&
- echo "lazy dog" >>file &&
- git add file &&
- GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
-
-test_expect_success $PREREQ \
- 'Setup helper tool' \
- '(echo "#!$SHELL_PATH"
- echo shift
- echo output=1
- echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
- echo for a
- echo do
- echo " echo \"!\$a!\""
- echo "done >commandline\$output"
- echo "cat > msgtxt\$output"
- ) >fake.sendmail &&
- chmod +x ./fake.sendmail &&
- git add fake.sendmail &&
- GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
-
-clean_fake_sendmail() {
+test_expect_success $PREREQ 'prepare reference tree' '
+ echo "1A quick brown fox jumps over the" >file &&
+ echo "lazy dog" >>file &&
+ git add file &&
+ GIT_AUTHOR_NAME="A" git commit -a -m "Initial."
+'
+
+test_expect_success $PREREQ 'Setup helper tool' '
+ write_script fake.sendmail <<-\EOF &&
+ shift
+ output=1
+ while test -f commandline$output
+ do
+ output=$(($output+1))
+ done
+ for a
+ do
+ echo "!$a!"
+ done >commandline$output
+ cat >"msgtxt$output"
+ EOF
+ git add fake.sendmail &&
+ GIT_AUTHOR_NAME="A" git commit -a -m "Second."
+'
+
+clean_fake_sendmail () {
rm -f commandline* msgtxt*
}
test_expect_success $PREREQ 'Extract patches' '
- patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
+ patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
'
# Test no confirm early to ensure remaining tests will not hang
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$@ \
- $patches > stdout &&
+ $patches >stdout &&
test_must_fail grep "Send this email" stdout &&
- > no_confirm_okay
+ >no_confirm_okay
}
# Exit immediately to prevent hang if a no-confirm test fails
'
test_expect_success $PREREQ 'Send patches' '
- git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+ git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+ cat >expected <<-\EOF
+ !nobody@example.com!
+ !author@example.com!
+ !one@example.com!
+ !two@example.com!
+ EOF
'
-test_expect_success $PREREQ \
- 'Verify commandline' \
- 'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+ test_cmp expected commandline1
+'
test_expect_success $PREREQ 'Send patches with --envelope-sender' '
- clean_fake_sendmail &&
- git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+ clean_fake_sendmail &&
+ git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!patch@example.com!
-!-i!
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+ cat >expected <<-\EOF
+ !patch@example.com!
+ !-i!
+ !nobody@example.com!
+ !author@example.com!
+ !one@example.com!
+ !two@example.com!
+ EOF
'
-test_expect_success $PREREQ \
- 'Verify commandline' \
- 'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+ test_cmp expected commandline1
+'
test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' '
- clean_fake_sendmail &&
- git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+ clean_fake_sendmail &&
+ git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!nobody@example.com!
-!-i!
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+ cat >expected <<-\EOF
+ !nobody@example.com!
+ !-i!
+ !nobody@example.com!
+ !author@example.com!
+ !one@example.com!
+ !two@example.com!
+ EOF
'
-test_expect_success $PREREQ \
- 'Verify commandline' \
- 'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+ test_cmp expected commandline1
+'
test_expect_success $PREREQ 'setup expect' "
cat >expected-show-all-headers <<\EOF
'non_ascii_self_suppressed'
"
+# This name is long enough to force format-patch to split it into multiple
+# encoded-words, assuming it uses UTF-8 with the "Q" encoding.
+test_expect_success $PREREQ 'long non-ascii self name is suppressed' "
+ test_suppress_self_quoted 'Ƒüñníęř €. Nâṁé' 'odd_?=mail@example.com' \
+ 'long_non_ascii_self_suppressed'
+"
+
test_expect_success $PREREQ 'sanitized self name is suppressed' "
test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \
'self_name_sanitized_suppressed'
clean_fake_sendmail &&
cp $patches tocmd.patch &&
echo tocmd--tocmd@example.com >>tocmd.patch &&
- {
- echo "#!$SHELL_PATH"
- echo sed -n -e s/^tocmd--//p \"\$1\"
- } > tocmd-sed &&
- chmod +x tocmd-sed &&
+ write_script tocmd-sed <<-\EOF &&
+ sed -n -e "s/^tocmd--//p" "$1"
+ EOF
git send-email \
--from="Example <nobody@example.com>" \
--to-cmd=./tocmd-sed \
clean_fake_sendmail &&
cp $patches cccmd.patch &&
echo "cccmd-- cccmd@example.com" >>cccmd.patch &&
- {
- echo "#!$SHELL_PATH"
- echo sed -n -e s/^cccmd--//p \"\$1\"
- } > cccmd-sed &&
- chmod +x cccmd-sed &&
+ write_script cccmd-sed <<-\EOF &&
+ sed -n -e "s/^cccmd--//p" "$1"
+ EOF
git send-email \
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$patches &&
- sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
+ sed "1,/^\$/d" <msgtxt1 >msgbody1 &&
grep "From: A <author@example.com>" msgbody1
'
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$patches &&
- sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
+ sed "1,/^\$/d" <msgtxt1 >msgbody1 &&
! grep "From: A <author@example.com>" msgbody1
'
'
test_expect_success $PREREQ 'setup fake editor' '
- (echo "#!$SHELL_PATH" &&
- echo "echo fake edit >>\"\$1\""
- ) >fake-editor &&
- chmod +x fake-editor
+ write_script fake-editor <<-\EOF
+ echo fake edit >>"$1"
+ EOF
'
test_set_editor "$(pwd)/fake-editor"
"
test_expect_success $PREREQ 'sendemail.cccmd' '
- echo echo cc-cmd@example.com > cccmd &&
- chmod +x cccmd &&
+ write_script cccmd <<-\EOF &&
+ echo cc-cmd@example.com
+ EOF
git config sendemail.cccmd ./cccmd &&
test_suppression cccmd
'
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- $@ $patches > stdout &&
+ $@ $patches >stdout &&
grep "Send this email" stdout
}
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- outdir/*.patch < /dev/null
+ outdir/*.patch </dev/null
ret="$?"
git config sendemail.confirm ${CONFIRM:-never}
test $ret = "0"
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- $patches < /dev/null
+ $patches </dev/null
ret="$?"
git config sendemail.confirm ${CONFIRM:-never}
test $ret = "0"
test_expect_success $PREREQ '--compose adds MIME for utf8 body' '
clean_fake_sendmail &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
'
test_expect_success $PREREQ '--compose respects user mime type' '
clean_fake_sendmail &&
- (echo "#!$SHELL_PATH" &&
- echo "(echo MIME-Version: 1.0"
- echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
- echo " echo Content-Transfer-Encoding: 8bit"
- echo " echo Subject: foo"
- echo " echo "
- echo " echo utf8 body: àéìöú) >\"\$1\""
- ) >fake-editor-utf8-mime &&
- chmod +x fake-editor-utf8-mime &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8-mime <<-\EOF &&
+ cat >"$1" <<-\EOM
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=iso-8859-1
+ Content-Transfer-Encoding: 8bit
+ Subject: foo
+
+ utf8 body: àéìöú
+ EOM
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
! grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
test_expect_success $PREREQ '--compose adds MIME for utf8 subject' '
clean_fake_sendmail &&
- GIT_EDITOR="\"$(pwd)/fake-editor\"" \
- git send-email \
- --compose --subject utf8-sübjëct \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+ git send-email \
+ --compose --subject utf8-sübjëct \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^fake edit" msgtxt1 &&
grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
'
git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
git format-patch --stdout -1 >funny_name.patch &&
git send-email --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- funny_name.patch &&
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ funny_name.patch &&
grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
'
git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
git format-patch --stdout -1 >funny_name.patch &&
git send-email --from="Füñný Nâmé <odd_?=mail@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- funny_name.patch &&
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ funny_name.patch &&
grep "^From: " msgtxt1 >msgfrom &&
test_line_count = 1 msgfrom
'
test_expect_success $PREREQ 'sendemail.composeencoding works' '
clean_fake_sendmail &&
git config sendemail.composeencoding iso-8859-1 &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
'
test_expect_success $PREREQ '--compose-encoding works' '
clean_fake_sendmail &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose-encoding iso-8859-1 \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose-encoding iso-8859-1 \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
'
test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' '
clean_fake_sendmail &&
git config sendemail.composeencoding iso-8859-1 &&
- (echo "#!$SHELL_PATH" &&
- echo "echo utf8 body: àéìöú >>\"\$1\""
- ) >fake-editor-utf8 &&
- chmod +x fake-editor-utf8 &&
- GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
- git send-email \
- --compose-encoding iso-8859-2 \
- --compose --subject foo \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ write_script fake-editor-utf8 <<-\EOF &&
+ echo "utf8 body: àéìöú" >>"$1"
+ EOF
+ GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+ git send-email \
+ --compose-encoding iso-8859-2 \
+ --compose --subject foo \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^utf8 body" msgtxt1 &&
grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1
'
test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' '
clean_fake_sendmail &&
- GIT_EDITOR="\"$(pwd)/fake-editor\"" \
- git send-email \
- --compose-encoding iso-8859-2 \
- --compose --subject utf8-sübjëct \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- $patches &&
+ GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+ git send-email \
+ --compose-encoding iso-8859-2 \
+ --compose --subject utf8-sübjëct \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches &&
grep "^fake edit" msgtxt1 &&
grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
'
test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
- echo master > master &&
+ echo master >master &&
git add master &&
git commit -m"add master" &&
test_must_fail git send-email --dry-run master 2>errors &&
rm -fr outdir &&
git format-patch -2 -o outdir &&
git send-email \
- --dry-run \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- outdir/000?-*.patch 2>errors >out &&
+ --dry-run \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ outdir/000?-*.patch 2>errors >out &&
grep "^Subject: " out >subjects &&
test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." &&
test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
'
test_expect_success $PREREQ 'setup expect' '
-cat >email-using-8bit <<EOF
+cat >email-using-8bit <<\EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
Message-Id: <bogus-message-id@example.com>
From: author@example.com
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<EOF
-Subject: subject goes here
-EOF
+ echo "Subject: subject goes here" >expected
'
test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
'
test_expect_success $PREREQ 'setup expect' '
-cat >content-type-decl <<EOF
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-EOF
+ cat >content-type-decl <<-\EOF
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+ EOF
'
test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
'
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: author@example.com
-Date: Sat, 12 Jun 2010 15:53:58 +0200
-Subject: Dieser Betreff enthält auch einen Umlaut!
-
-Nothing to see here.
-EOF
+ cat >email-using-8bit <<-\EOF
+ From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+ Message-Id: <bogus-message-id@example.com>
+ From: author@example.com
+ Date: Sat, 12 Jun 2010 15:53:58 +0200
+ Subject: Dieser Betreff enthält auch einen Umlaut!
+
+ Nothing to see here.
+ EOF
'
test_expect_success $PREREQ 'setup expect' '
-cat >expected <<EOF
-Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
-EOF
+ cat >expected <<-\EOF
+ Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
+ EOF
'
test_expect_success $PREREQ '--8bit-encoding also treats subject' '
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.
rm -fr outdir &&
git format-patch --cover-letter -2 -o outdir &&
test_must_fail git send-email \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0002-*.patch \
- outdir/0000-*.patch \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0002-*.patch \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ 2>errors >out &&
grep "SUBJECT HERE" errors &&
test -z "$(ls msgtxt*)"
'
rm -fr outdir &&
git format-patch --cover-letter -2 -o outdir &&
git send-email \
- --force \
- --from="Example <nobody@example.com>" \
- --to=nobody@example.com \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0002-*.patch \
- outdir/0000-*.patch \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --force \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0002-*.patch \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ 2>errors >out &&
! grep "SUBJECT HERE" errors &&
test -n "$(ls msgtxt*)"
'
mv $cover cover-to-edit.patch &&
perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" &&
git send-email \
- --force \
- --from="Example <nobody@example.com>" \
- --no-to --no-cc \
- "$@" \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0000-*.patch \
- outdir/0001-*.patch \
- outdir/0002-*.patch \
- 2>errors >out &&
+ --force \
+ --from="Example <nobody@example.com>" \
+ --no-to --no-cc \
+ "$@" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ outdir/0002-*.patch \
+ 2>errors >out &&
grep "^$header: extra@address.com" msgtxt1 >to1 &&
grep "^$header: extra@address.com" msgtxt2 >to2 &&
grep "^$header: extra@address.com" msgtxt3 >to3 &&
git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" &&
git config sendemail.aliasfiletype mailrc &&
git send-email \
- --from="Example <nobody@example.com>" \
- --to=sbd \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --from="Example <nobody@example.com>" \
+ --to=sbd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0001-*.patch \
+ 2>errors >out &&
grep "^!somebody@example\.org!$" commandline1
'
git config --replace-all sendemail.aliasesfile "~/.mailrc" &&
git config sendemail.aliasfiletype mailrc &&
git send-email \
- --from="Example <nobody@example.com>" \
- --to=sbd \
- --smtp-server="$(pwd)/fake.sendmail" \
- outdir/0001-*.patch \
- 2>errors >out &&
+ --from="Example <nobody@example.com>" \
+ --to=sbd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0001-*.patch \
+ 2>errors >out &&
grep "^!someone@example\.org!$" commandline1
'
+do_xmailer_test () {
+ expected=$1 params=$2 &&
+ git format-patch -1 &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=someone@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $params \
+ 0001-*.patch \
+ 2>errors >out &&
+ { grep '^X-Mailer:' out || :; } >mailer &&
+ test_line_count = $expected mailer
+}
+
+test_expect_success $PREREQ '--[no-]xmailer without any configuration' '
+ do_xmailer_test 1 "--xmailer" &&
+ do_xmailer_test 0 "--no-xmailer"
+'
+
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=true' '
+ test_config sendemail.xmailer true &&
+ do_xmailer_test 1 "" &&
+ do_xmailer_test 0 "--no-xmailer" &&
+ do_xmailer_test 1 "--xmailer"
+'
+
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '
+ test_config sendemail.xmailer false &&
+ do_xmailer_test 0 "" &&
+ do_xmailer_test 0 "--no-xmailer" &&
+ do_xmailer_test 1 "--xmailer"
+'
+
test_done
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2014 Alfred Perlstein
+#
+
+test_description='git svn propset tests'
+
+. ./lib-git-svn.sh
+
+foo_subdir2="subdir/subdir2/foo_subdir2"
+
+set -e
+mkdir import &&
+(set -e ; cd import
+ mkdir subdir
+ mkdir subdir/subdir2
+ touch foo # for 'add props top level'
+ touch subdir/foo_subdir # for 'add props relative'
+ touch "$foo_subdir2" # for 'add props subdir'
+ svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null
+)
+rm -rf import
+
+test_expect_success 'initialize git svn' '
+ git svn init "$svnrepo"
+ '
+
+test_expect_success 'fetch revisions from svn' '
+ git svn fetch
+ '
+
+set_props () {
+ subdir="$1"
+ file="$2"
+ shift;shift;
+ (cd "$subdir" &&
+ while [ $# -gt 0 ] ; do
+ git svn propset "$1" "$2" "$file" || exit 1
+ shift;shift;
+ done &&
+ echo hello >> "$file" &&
+ git commit -m "testing propset" "$file")
+}
+
+confirm_props () {
+ subdir="$1"
+ file="$2"
+ shift;shift;
+ (set -e ; cd "svn_project/$subdir" &&
+ while [ $# -gt 0 ] ; do
+ test "$(svn_cmd propget "$1" "$file")" = "$2" || exit 1
+ shift;shift;
+ done)
+}
+
+
+#The current implementation has a restriction:
+#svn propset will be taken as a delta for svn dcommit only
+#if the file content is also modified
+test_expect_success 'add props top level' '
+ set_props "." "foo" "svn:keywords" "FreeBSD=%H" &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "." "foo" "svn:keywords" "FreeBSD=%H" &&
+ rm -rf svn_project
+ '
+
+test_expect_success 'add multiple props' '
+ set_props "." "foo" \
+ "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "." "foo" \
+ "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes &&
+ rm -rf svn_project
+ '
+
+test_expect_success 'add props subdir' '
+ set_props "." "$foo_subdir2" svn:keywords "FreeBSD=%H" &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "." "$foo_subdir2" "svn:keywords" "FreeBSD=%H" &&
+ rm -rf svn_project
+ '
+
+test_expect_success 'add props relative' '
+ set_props "subdir/subdir2" "../foo_subdir" \
+ svn:keywords "FreeBSD=%H" &&
+ git svn dcommit &&
+ svn_cmd co "$svnrepo" svn_project &&
+ confirm_props "subdir/subdir2" "../foo_subdir" \
+ svn:keywords "FreeBSD=%H" &&
+ rm -rf svn_project
+ '
+test_done
git commit -m "another b2" file &&
echo 000 >file &&
git commit -m "yet another b2" file &&
+ mkdir ignored_dir &&
+ echo "ignored_dir/" >>.gitignore &&
git checkout master
'
test_cmp expected "$actual"
'
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled' '
+ printf " (master)" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled, pc mode' '
+ printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset' '
+ printf " (master)" >expected &&
+ (
+ cd ignored_dir &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset, pc mode' '
+ printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
+ (
+ cd ignored_dir &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled' '
+ printf " (master)" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled, pc mode' '
+ printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
+ test_config bash.hideIfPwdIgnored false &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config unset' '
+ printf "" >expected &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - env var set, config unset, pc mode' '
+ printf "BEFORE::AFTER" >expected &&
+ (
+ cd ignored_dir &&
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ __git_ps1 "BEFORE:" ":AFTER" &&
+ printf "%s" "$PS1" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - inside gitdir (stdout)' '
+ printf " (GIT_DIR!)" >expected &&
+ (
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ cd .git &&
+ __git_ps1 >"$actual" 2>/dev/null
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'prompt - hide if pwd ignored - inside gitdir (stderr)' '
+ printf "" >expected &&
+ (
+ GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
+ cd .git &&
+ __git_ps1 >/dev/null 2>"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
test_done
}
fi
+: ${ASAN_OPTIONS=detect_leaks=0}
+export ASAN_OPTIONS
+
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH
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:
#
# This test checks if command xyzzy does the right thing...
# '
# . ./test-lib.sh
-[ "x$ORIGINAL_TERM" != "xdumb" ] && (
- TERM=$ORIGINAL_TERM &&
- export TERM &&
- [ -t 1 ] &&
- tput bold >/dev/null 2>&1 &&
- tput setaf 1 >/dev/null 2>&1 &&
- tput sgr0 >/dev/null 2>&1
- ) &&
- color=t
+unset color
while test "$#" -ne 0
do
case "$1" in
verbose=t
fi
-if test -n "$color"
-then
- say_color () {
- (
- TERM=$ORIGINAL_TERM
- export TERM
- case "$1" in
- error)
- tput bold; tput setaf 1;; # bold red
- skip)
- tput setaf 4;; # blue
- warn)
- tput setaf 3;; # brown/yellow
- pass)
- tput setaf 2;; # green
- info)
- tput setaf 6;; # cyan
- *)
- test -n "$quiet" && return;;
- esac
- shift
- printf "%s" "$*"
- tput sgr0
- echo
- )
- }
-else
- say_color() {
- test -z "$1" && test -n "$quiet" && return
- shift
- printf "%s\n" "$*"
- }
-fi
-
error () {
say_color error "error: $*"
GIT_EXIT_OK=t
then
error "Can't use skip_all after running some tests"
fi
- [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
+ test -z "$skip_all" || skip_all=" # SKIP $skip_all"
if test $test_external_has_tap -eq 0
then
GNUPGHOME="$HOME/gnupg-home-not-used"
export HOME GNUPGHOME
+# run the tput tests *after* changing HOME (in case ncurses needs
+# ~/.terminfo for $TERM)
+test -n "${color+set}" || test "x$ORIGINAL_TERM" != "xdumb" && (
+ TERM=$ORIGINAL_TERM &&
+ export TERM &&
+ test -t 1 &&
+ tput bold >/dev/null 2>&1 &&
+ tput setaf 1 >/dev/null 2>&1 &&
+ tput sgr0 >/dev/null 2>&1
+ ) &&
+ color=t
+
+if test -n "$color"
+then
+ say_color () {
+ (
+ TERM=$ORIGINAL_TERM
+ export TERM
+ case "$1" in
+ error)
+ tput bold; tput setaf 1;; # bold red
+ skip)
+ tput setaf 4;; # blue
+ warn)
+ tput setaf 3;; # brown/yellow
+ pass)
+ tput setaf 2;; # green
+ info)
+ tput setaf 6;; # cyan
+ *)
+ test -n "$quiet" && return;;
+ esac
+ shift
+ printf "%s" "$*"
+ tput sgr0
+ echo
+ )
+ }
+else
+ say_color() {
+ test -z "$1" && test -n "$quiet" && return
+ shift
+ printf "%s\n" "$*"
+ }
+fi
+
if test -z "$TEST_NO_CREATE_REPO"
then
test_create_repo "$TRASH_DIRECTORY"
z40=0000000000000000000000000000000000000000
-IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
if [ "$local_sha" = $z40 ]
static unsigned int hash(unsigned int method, unsigned int i, const char *key)
{
- unsigned int hash;
+ unsigned int hash = 0;
switch (method & 3)
{
case HASH_METHOD_FNV:
static void print_trace_line(struct trace_key *key, struct strbuf *buf)
{
- /* append newline if missing */
- if (buf->len && buf->buf[buf->len - 1] != '\n')
- strbuf_addch(buf, '\n');
+ strbuf_complete_line(buf);
write_or_whine_pipe(get_trace_fd(key), buf->buf, buf->len, err_msg);
strbuf_release(buf);
return !!get_trace_fd(key);
}
-#ifdef HAVE_CLOCK_GETTIME
+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
static inline uint64_t highres_nanos(void)
{
#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);
}
} else {
/* Unknown protocol in URL. Pass to external handler. */
int len = external_specification_len(url);
- char *handler = xmalloc(len + 1);
- handler[len] = 0;
- strncpy(handler, url, len);
+ char *handler = xmemdupz(url, len);
transport_helper_init(ret, handler);
}
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;
}
fi &&
make
) &&
- echo "static const struct interval zero_width[] = {" >$UNICODEWIDTH_H &&
- UNICODE_DIR=. ./uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
- grep -v plane >>$UNICODEWIDTH_H &&
- echo "};" >>$UNICODEWIDTH_H &&
- echo "static const struct interval double_width[] = {" >>$UNICODEWIDTH_H &&
- UNICODE_DIR=. ./uniset/uniset --32 eaw:F,W >>$UNICODEWIDTH_H &&
- echo "};" >>$UNICODEWIDTH_H
+ UNICODE_DIR=. && export UNICODE_DIR &&
+ cat >$UNICODEWIDTH_H <<-EOF
+ static const struct interval zero_width[] = {
+ $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
+ grep -v plane)
+ };
+ static const struct interval double_width[] = {
+ $(uniset/uniset --32 eaw:F,W)
+ };
+ EOF
)
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[12];
+ const char *argv[13];
int i, arg = 0;
FILE *pipe_fd;
argv[arg++] = "--thin";
argv[arg++] = "--stdout";
+ if (shallow_nr)
+ argv[arg++] = "--shallow";
if (!no_progress)
argv[arg++] = "--progress";
if (use_ofs_delta)
return chrlen;
}
+
+/*
+ * Pick the next char from the stream, ignoring codepoints an HFS+ 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;
+ }
+
+ return out;
+ }
+}
+
+int is_hfs_dotgit(const char *path)
+{
+ ucs_char_t c;
+
+ c = next_hfs_char(&path);
+ if (c != '.')
+ return 0;
+ c = next_hfs_char(&path);
+
+ /*
+ * there's a great deal of other case-folding that occurs
+ * in HFS+, but this is enough to catch anything that will
+ * convert to ".git"
+ */
+ if (c != 'g' && c != 'G')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c != 'i' && c != 'I')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c != 't' && c != '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