зеркало из https://github.com/microsoft/git.git
Start maintenance track for 2.10.x series
This commit is contained in:
Коммит
49981d8a25
1
.mailmap
1
.mailmap
|
@ -33,6 +33,7 @@ Cheng Renquan <crquan@gmail.com>
|
|||
Chris Shoemaker <c.shoemaker@cox.net>
|
||||
Chris Wright <chrisw@sous-sol.org> <chrisw@osdl.org>
|
||||
Cord Seele <cowose@gmail.com> <cowose@googlemail.com>
|
||||
Christian Couder <chriscool@tuxfamily.org> <christian.couder@gmail.com>
|
||||
Christian Stimming <stimming@tuhh.de> <chs@ckiste.goetheallee>
|
||||
Csaba Henk <csaba@gluster.com> <csaba@lowlife.hu>
|
||||
Dan Johnson <computerdruid@gmail.com>
|
||||
|
|
|
@ -0,0 +1,675 @@
|
|||
Git 2.10 Release Notes
|
||||
======================
|
||||
|
||||
Backward compatibility notes
|
||||
----------------------------
|
||||
|
||||
Updates since v2.9
|
||||
------------------
|
||||
|
||||
UI, Workflows & Features
|
||||
|
||||
* "git pull --rebase --verify-signature" learned to warn the user
|
||||
that "--verify-signature" is a no-op when rebasing.
|
||||
|
||||
* An upstream project can make a recommendation to shallowly clone
|
||||
some submodules in the .gitmodules file it ships.
|
||||
|
||||
* "git worktree add" learned that '-' can be used as a short-hand for
|
||||
"@{-1}", the previous branch.
|
||||
|
||||
* Update the funcname definition to support css files.
|
||||
|
||||
* The completion script (in contrib/) learned to complete "git
|
||||
status" options.
|
||||
|
||||
* Messages that are generated by auto gc during "git push" on the
|
||||
receiving end are now passed back to the sending end in such a way
|
||||
that they are shown with "remote: " prefix to avoid confusing the
|
||||
users.
|
||||
|
||||
* "git add -i/-p" learned to honor diff.compactionHeuristic
|
||||
experimental knob, so that the user can work on the same hunk split
|
||||
as "git diff" output.
|
||||
|
||||
* "upload-pack" allows a custom "git pack-objects" replacement when
|
||||
responding to "fetch/clone" via the uploadpack.packObjectsHook.
|
||||
(merge b738396 jk/upload-pack-hook later to maint).
|
||||
|
||||
* Teach format-patch and mailsplit (hence "am") how a line that
|
||||
happens to begin with "From " in the e-mail message is quoted with
|
||||
">", so that these lines can be restored to their original shape.
|
||||
(merge d9925d1 ew/mboxrd-format-am later to maint).
|
||||
|
||||
* "git repack" learned the "--keep-unreachable" option, which sends
|
||||
loose unreachable objects to a pack instead of leaving them loose.
|
||||
This helps heuristics based on the number of loose objects
|
||||
(e.g. "gc --auto").
|
||||
(merge e26a8c4 jk/repack-keep-unreachable later to maint).
|
||||
|
||||
* "log --graph --format=" learned that "%>|(N)" specifies the width
|
||||
relative to the terminal's left edge, not relative to the area to
|
||||
draw text that is to the right of the ancestry-graph section. It
|
||||
also now accepts negative N that means the column limit is relative
|
||||
to the right border.
|
||||
|
||||
* A careless invocation of "git send-email directory/" after editing
|
||||
0001-change.patch with an editor often ends up sending both
|
||||
0001-change.patch and its backup file, 0001-change.patch~, causing
|
||||
embarrassment and a minor confusion. Detect such an input and
|
||||
offer to skip the backup files when sending the patches out.
|
||||
(merge 531220b jc/send-email-skip-backup later to maint).
|
||||
|
||||
* "git submodule update" that drives many "git clone" could
|
||||
eventually hit flaky servers/network conditions on one of the
|
||||
submodules; the command learned to retry the attempt.
|
||||
|
||||
* The output coloring scheme learned two new attributes, italic and
|
||||
strike, in addition to existing bold, reverse, etc.
|
||||
|
||||
* "git log" learns log.showSignature configuration variable, and a
|
||||
command line option "--no-show-signature" to countermand it.
|
||||
(merge fce04c3 mj/log-show-signature-conf later to maint).
|
||||
|
||||
* More markings of messages for i18n, with updates to various tests
|
||||
to pass GETTEXT_POISON tests.
|
||||
|
||||
* "git archive" learned to handle files that are larger than 8GB and
|
||||
commits far in the future than expressible by the traditional US-TAR
|
||||
format.
|
||||
(merge 560b0e8 jk/big-and-future-archive-tar later to maint).
|
||||
|
||||
|
||||
* A new configuration variable core.sshCommand has been added to
|
||||
specify what value for GIT_SSH_COMMAND to use per repository.
|
||||
|
||||
* "git worktree prune" protected worktrees that are marked as
|
||||
"locked" by creating a file in a known location. "git worktree"
|
||||
command learned a dedicated command pair to create and remove such
|
||||
a file, so that the users do not have to do this with editor.
|
||||
|
||||
* A handful of "git svn" updates.
|
||||
|
||||
* "git push" learned to accept and pass extra options to the
|
||||
receiving end so that hooks can read and react to them.
|
||||
|
||||
* "git status" learned to suggest "merge --abort" during a conflicted
|
||||
merge, just like it already suggests "rebase --abort" during a
|
||||
conflicted rebase.
|
||||
|
||||
* "git jump" script (in contrib/) has been updated a bit.
|
||||
(merge a91e692 jk/git-jump later to maint).
|
||||
|
||||
* "git push" and "git clone" learned to give better progress meters
|
||||
to the end user who is waiting on the terminal.
|
||||
|
||||
* An entry "git log --decorate" for the tip of the current branch is
|
||||
shown as "HEAD -> name" (where "name" is the name of the branch);
|
||||
the arrow is now painted in the same color as "HEAD", not in the
|
||||
color for commits.
|
||||
|
||||
* "git format-patch" learned format.from configuration variable to
|
||||
specify the default settings for its "--from" option.
|
||||
|
||||
* "git am -3" calls "git merge-recursive" when it needs to fall back
|
||||
to a three-way merge; this call has been turned into an internal
|
||||
subroutine call instead of spawning a separate subprocess.
|
||||
|
||||
* The command line completion scripts (in contrib/) now knows about
|
||||
"git branch --delete/--move [--remote]".
|
||||
(merge 2703c22 vs/completion-branch-fully-spelled-d-m-r later to maint).
|
||||
|
||||
* "git rev-parse --git-path hooks/<hook>" learned to take
|
||||
core.hooksPath configuration variable (introduced during 2.9 cycle)
|
||||
into account.
|
||||
(merge 9445b49 ab/hooks later to maint).
|
||||
|
||||
* "git log --show-signature" and other commands that display the
|
||||
verification status of PGP signature now shows the longer key-id,
|
||||
as 32-bit key-id is so last century.
|
||||
|
||||
|
||||
Performance, Internal Implementation, Development Support etc.
|
||||
|
||||
* "git fast-import" learned the same performance trick to avoid
|
||||
creating too small a packfile as "git fetch" and "git push" have,
|
||||
using *.unpackLimit configuration.
|
||||
|
||||
* When "git daemon" is run without --[init-]timeout specified, a
|
||||
connection from a client that silently goes offline can hang around
|
||||
for a long time, wasting resources. The socket-level KEEPALIVE has
|
||||
been enabled to allow the OS to notice such failed connections.
|
||||
|
||||
* "git upload-pack" command has been updated to use the parse-options
|
||||
API.
|
||||
|
||||
* The "git apply" standalone program is being libified; the first
|
||||
step to move many state variables into a structure that can be
|
||||
explicitly (re)initialized to make the machinery callable more
|
||||
than once has been merged.
|
||||
|
||||
* HTTP transport gained an option to produce more detailed debugging
|
||||
trace.
|
||||
(merge 73e57aa ep/http-curl-trace later to maint).
|
||||
|
||||
* Instead of taking advantage of the fact that a struct string_list
|
||||
that is allocated with all NULs happens to be the INIT_NODUP kind,
|
||||
the users of string_list structures are taught to initialize them
|
||||
explicitly as such, to document their behaviour better.
|
||||
(merge 2721ce2 jk/string-list-static-init later to maint).
|
||||
|
||||
* HTTPd tests learned to show the server error log to help diagnosing
|
||||
a failing tests.
|
||||
(merge 44f243d nd/test-lib-httpd-show-error-log-in-verbose later to maint).
|
||||
|
||||
* The ownership rule for the piece of memory that hold references to
|
||||
be fetched in "git fetch" was screwy, which has been cleaned up.
|
||||
|
||||
* "git bisect" makes an internal call to "git diff-tree" when
|
||||
bisection finds the culprit, but this call did not initialize the
|
||||
data structure to pass to the diff-tree API correctly.
|
||||
|
||||
* Further preparatory clean-up for "worktree" feature continues.
|
||||
(merge 0409e0b nd/worktree-cleanup-post-head-protection later to maint).
|
||||
|
||||
* Formats of the various data (and how to validate them) where we use
|
||||
GPG signature have been documented.
|
||||
|
||||
* A new run-command API function pipe_command() is introduced to
|
||||
sanely feed data to the standard input while capturing data from
|
||||
the standard output and the standard error of an external process,
|
||||
which is cumbersome to hand-roll correctly without deadlocking.
|
||||
|
||||
* The codepath to sign data in a prepared buffer with GPG has been
|
||||
updated to use this API to read from the status-fd to check for
|
||||
errors (instead of relying on GPG's exit status).
|
||||
(merge efee955 jk/gpg-interface-cleanup later to maint).
|
||||
|
||||
* Allow t/perf framework to use the features from the most recent
|
||||
version of Git even when testing an older installed version.
|
||||
|
||||
* The commands in the "log/diff" family have had an FILE* pointer in the
|
||||
data structure they pass around for a long time, but some codepaths
|
||||
used to always write to the standard output. As a preparatory step
|
||||
to make "git format-patch" available to the internal callers, these
|
||||
codepaths have been updated to consistently write into that FILE*
|
||||
instead.
|
||||
|
||||
* Conversion from unsigned char sha1[20] to struct object_id
|
||||
continues.
|
||||
|
||||
* Improve the look of the way "git fetch" reports what happened to
|
||||
each ref that was fetched.
|
||||
|
||||
* The .c/.h sources are marked as such in our .gitattributes file so
|
||||
that "git diff -W" and friends would work better.
|
||||
|
||||
* Code clean-up to avoid using a variable string that compilers may
|
||||
feel untrustable as printf-style format given to write_file()
|
||||
helper function.
|
||||
|
||||
* "git p4" used a location outside $GIT_DIR/refs/ to place its
|
||||
temporary branches, which has been moved to refs/git-p4-tmp/.
|
||||
|
||||
* Existing autoconf generated test for the need to link with pthread
|
||||
library did not check all the functions from pthread libraries;
|
||||
recent FreeBSD has some functions in libc but not others, and we
|
||||
mistakenly thought linking with libc is enough when it is not.
|
||||
|
||||
* When "git fsck" reports a broken link (e.g. a tree object contains
|
||||
a blob that does not exist), both containing object and the object
|
||||
that is referred to were reported with their 40-hex object names.
|
||||
The command learned the "--name-objects" option to show the path to
|
||||
the containing object from existing refs (e.g. "HEAD~24^2:file.txt").
|
||||
|
||||
* Allow http daemon tests in Travis CI tests.
|
||||
|
||||
* Makefile assumed that -lrt is always available on platforms that
|
||||
want to use clock_gettime() and CLOCK_MONOTONIC, which is not a
|
||||
case for recent Mac OS X. The necessary symbols are often found in
|
||||
libc on many modern systems and having -lrt on the command line, as
|
||||
long as the library exists, had no effect, but when the platform
|
||||
removes librt.a that is a different matter--having -lrt will break
|
||||
the linkage.
|
||||
|
||||
This change could be seen as a regression for those who do need to
|
||||
specify -lrt, as they now specifically ask for NEEDS_LIBRT when
|
||||
building. Hopefully they are in the minority these days.
|
||||
|
||||
* Further preparatory work on the refs API before the pluggable
|
||||
backend series can land.
|
||||
|
||||
* Error handling in the codepaths that updates refs has been
|
||||
improved.
|
||||
|
||||
* The API to iterate over all the refs (i.e. for_each_ref(), etc.)
|
||||
has been revamped.
|
||||
|
||||
* The handling of the "text=auto" attribute has been corrected.
|
||||
$ echo "* text=auto eol=crlf" >.gitattributes
|
||||
used to have the same effect as
|
||||
$ echo "* text eol=crlf" >.gitattributes
|
||||
i.e. declaring all files are text (ignoring "auto"). The
|
||||
combination has been fixed to be equivalent to doing
|
||||
$ git config core.autocrlf true
|
||||
|
||||
* Documentation has been updated to show better example usage
|
||||
of the updated "text=auto" attribute.
|
||||
|
||||
* A few tests that specifically target "git rebase -i" have been
|
||||
added.
|
||||
|
||||
* Dumb http transport on the client side has been optimized.
|
||||
(merge ecba195 ew/http-walker later to maint).
|
||||
|
||||
* Users of the parse_options_concat() API function need to allocate
|
||||
extra slots in advance and fill them with OPT_END() when they want
|
||||
to decide the set of supported options dynamically, which makes the
|
||||
code error-prone and hard to read. This has been corrected by tweaking
|
||||
the API to allocate and return a new copy of "struct option" array.
|
||||
|
||||
* "git fetch" exchanges batched have/ack messages between the sender
|
||||
and the receiver, initially doubling every time and then falling
|
||||
back to enlarge the window size linearly. The "smart http"
|
||||
transport, being an half-duplex protocol, outgrows the preset limit
|
||||
too quickly and becomes inefficient when interacting with a large
|
||||
repository. The internal mechanism learned to grow the window size
|
||||
more aggressively when working with the "smart http" transport.
|
||||
|
||||
* Tests for "git svn" have been taught to reuse the lib-httpd test
|
||||
infrastructure when testing the subversion integration that
|
||||
interacts with subversion repositories served over the http://
|
||||
protocol.
|
||||
(merge a8a5d25 ew/git-svn-http-tests later to maint).
|
||||
|
||||
* "git pack-objects" has a few options that tell it not to pack
|
||||
objects found in certain packfiles, which require it to scan .idx
|
||||
files of all available packs. The codepaths involved in these
|
||||
operations have been optimized for a common case of not having any
|
||||
non-local pack and/or any .kept pack.
|
||||
|
||||
* The t3700 test about "add --chmod=-x" have been made a bit more
|
||||
robust and generally cleaned up.
|
||||
(merge 766cdc4 ib/t3700-add-chmod-x-updates later to maint).
|
||||
|
||||
* The build procedure learned PAGER_ENV knob that lists what default
|
||||
environment variable settings to export for popular pagers. This
|
||||
mechanism is used to tweak the default settings to MORE on FreeBSD.
|
||||
(merge 995bc22 ew/build-time-pager-tweaks later to maint).
|
||||
|
||||
* The http-backend (the server-side component of smart-http
|
||||
transport) used to trickle the HTTP header one at a time. Now
|
||||
these write(2)s are batched.
|
||||
(merge b36045c ew/http-backend-batch-headers later to maint).
|
||||
|
||||
* When "git rebase" tries to compare set of changes on the updated
|
||||
upstream and our own branch, it computes patch-id for all of these
|
||||
changes and attempts to find matches. This has been optimized by
|
||||
lazily computing the full patch-id (which is expensive) to be
|
||||
compared only for changes that touch the same set of paths.
|
||||
(merge ba67504 kw/patch-ids-optim later to maint).
|
||||
|
||||
* A handful of tests that were broken under gettext-poison build have
|
||||
been fixed.
|
||||
|
||||
* The recent i18n patch we added during this cycle did a bit too much
|
||||
refactoring of the messages to avoid word-legos; the repetition has
|
||||
been reduced to help translators.
|
||||
|
||||
|
||||
Also contains various documentation updates and code clean-ups.
|
||||
|
||||
|
||||
Fixes since v2.9
|
||||
----------------
|
||||
|
||||
Unless otherwise noted, all the fixes since v2.8 in the maintenance
|
||||
track are contained in this release (see the maintenance releases'
|
||||
notes for details).
|
||||
|
||||
* The commands in `git log` family take %C(auto) in a custom format
|
||||
string. This unconditionally turned the color on, ignoring
|
||||
--no-color or with --color=auto when the output is not connected to
|
||||
a tty; this was corrected to make the format truly behave as
|
||||
"auto".
|
||||
|
||||
* "git rev-list --count" whose walk-length is limited with "-n"
|
||||
option did not work well with the counting optimized to look at the
|
||||
bitmap index.
|
||||
|
||||
* "git show -W" (extend hunks to cover the entire function, delimited
|
||||
by lines that match the "funcname" pattern) used to show the entire
|
||||
file when a change added an entire function at the end of the file,
|
||||
which has been fixed.
|
||||
|
||||
* The documentation set has been updated so that literal commands,
|
||||
configuration variables and environment variables are consistently
|
||||
typeset in fixed-width font and bold in manpages.
|
||||
|
||||
* "git svn propset" subcommand that was added in 2.3 days is
|
||||
documented now.
|
||||
|
||||
* The documentation tries to consistently spell "GPG"; when
|
||||
referring to the specific program name, "gpg" is used.
|
||||
|
||||
* "git reflog" stopped upon seeing an entry that denotes a branch
|
||||
creation event (aka "unborn"), which made it appear as if the
|
||||
reflog was truncated.
|
||||
|
||||
* The git-prompt scriptlet (in contrib/) was not friendly with those
|
||||
who uses "set -u", which has been fixed.
|
||||
|
||||
* compat/regex code did not cleanly compile.
|
||||
|
||||
* A codepath that used alloca(3) to place an unbounded amount of data
|
||||
on the stack has been updated to avoid doing so.
|
||||
|
||||
* "git update-index --add --chmod=+x file" may be usable as an escape
|
||||
hatch, but not a friendly thing to force for people who do need to
|
||||
use it regularly. "git add --chmod=+x file" can be used instead.
|
||||
|
||||
* Build improvements for gnome-keyring (in contrib/)
|
||||
|
||||
* "git status" used to say "working directory" when it meant "working
|
||||
tree".
|
||||
|
||||
* Comments about misbehaving FreeBSD shells have been clarified with
|
||||
the version number (9.x and before are broken, newer ones are OK).
|
||||
|
||||
* "git cherry-pick A" worked on an unborn branch, but "git
|
||||
cherry-pick A..B" didn't.
|
||||
|
||||
* Fix an unintended regression in v2.9 that breaks "clone --depth"
|
||||
that recurses down to submodules by forcing the submodules to also
|
||||
be cloned shallowly, which many server instances that host upstream
|
||||
of the submodules are not prepared for.
|
||||
|
||||
* Fix unnecessarily waste in the idiomatic use of ': ${VAR=default}'
|
||||
to set the default value, without enclosing it in double quotes.
|
||||
|
||||
* Some platform-specific code had non-ANSI strict declarations of C
|
||||
functions that do not take any parameters, which has been
|
||||
corrected.
|
||||
|
||||
* The internal code used to show local timezone offset is not
|
||||
prepared to handle timestamps beyond year 2100, and gave a
|
||||
bogus offset value to the caller. Use a more benign looking
|
||||
+0000 instead and let "git log" going in such a case, instead
|
||||
of aborting.
|
||||
|
||||
* One among four invocations of readlink(1) in our test suite has
|
||||
been rewritten so that the test can run on systems without the
|
||||
command (others are in valgrind test framework and t9802).
|
||||
|
||||
* t/perf needs /usr/bin/time with GNU extension; the invocation of it
|
||||
is updated to "gtime" on Darwin.
|
||||
|
||||
* A bug, which caused "git p4" while running under verbose mode to
|
||||
report paths that are omitted due to branch prefix incorrectly, has
|
||||
been fixed; the command said "Ignoring file outside of prefix" for
|
||||
paths that are _inside_.
|
||||
|
||||
* The top level documentation "git help git" still pointed at the
|
||||
documentation set hosted at now-defunct google-code repository.
|
||||
Update it to point to https://git.github.io/htmldocs/git.html
|
||||
instead.
|
||||
|
||||
* A helper function that takes the contents of a commit object and
|
||||
finds its subject line did not ignore leading blank lines, as is
|
||||
commonly done by other codepaths. Make it ignore leading blank
|
||||
lines to match.
|
||||
|
||||
* For a long time, we carried an in-code comment that said our
|
||||
colored output would work only when we use fprintf/fputs on
|
||||
Windows, which no longer is the case for the past few years.
|
||||
|
||||
* "gc.autoPackLimit" when set to 1 should not trigger a repacking
|
||||
when there is only one pack, but the code counted poorly and did
|
||||
so.
|
||||
|
||||
* Add a test to specify the desired behaviour that currently is not
|
||||
available in "git rebase -Xsubtree=...".
|
||||
|
||||
* More mark-up updates to typeset strings that are expected to
|
||||
literally typed by the end user in fixed-width font.
|
||||
|
||||
* "git commit --amend --allow-empty-message -S" for a commit without
|
||||
any message body could have misidentified where the header of the
|
||||
commit object ends.
|
||||
|
||||
* "git rebase -i --autostash" did not restore the auto-stashed change
|
||||
when the operation was aborted.
|
||||
|
||||
* Git does not know what the contents in the index should be for a
|
||||
path added with "git add -N" yet, so "git grep --cached" should not
|
||||
show hits (or show lack of hits, with -L) in such a path, but that
|
||||
logic does not apply to "git grep", i.e. searching in the working
|
||||
tree files. But we did so by mistake, which has been corrected.
|
||||
|
||||
* "git blame -M" missed a single line that was moved within the file.
|
||||
|
||||
* Fix recently introduced codepaths that are involved in parallel
|
||||
submodule operations, which gave up on reading too early, and
|
||||
could have wasted CPU while attempting to write under a corner
|
||||
case condition.
|
||||
|
||||
* "git grep -i" has been taught to fold case in non-ascii locales
|
||||
correctly.
|
||||
|
||||
* A test that unconditionally used "mktemp" learned that the command
|
||||
is not necessarily available everywhere.
|
||||
|
||||
* There are certain house-keeping tasks that need to be performed at
|
||||
the very beginning of any Git program, and programs that are not
|
||||
built-in commands had to do them exactly the same way as "git"
|
||||
potty does. It was easy to make mistakes in one-off standalone
|
||||
programs (like test helpers). A common "main()" function that
|
||||
calls cmd_main() of individual program has been introduced to
|
||||
make it harder to make mistakes.
|
||||
(merge de61ceb jk/common-main later to maint).
|
||||
|
||||
* The test framework learned a new helper test_match_signal to
|
||||
check an exit code from getting killed by an expected signal.
|
||||
|
||||
* General code clean-up around a helper function to write a
|
||||
single-liner to a file.
|
||||
(merge 7eb6e10 jk/write-file later to maint).
|
||||
|
||||
* One part of "git am" had an oddball helper function that called
|
||||
stuff from outside "his" as opposed to calling what we have "ours",
|
||||
which was not gender-neutral and also inconsistent with the rest of
|
||||
the system where outside stuff is usuall called "theirs" in
|
||||
contrast to "ours".
|
||||
|
||||
* "git blame file" allowed the lineage of lines in the uncommitted,
|
||||
unadded contents of "file" to be inspected, but it refused when
|
||||
"file" did not appear in the current commit. When "file" was
|
||||
created by renaming an existing file (but the change has not been
|
||||
committed), this restriction was unnecessarily tight.
|
||||
|
||||
* "git add -N dir/file && git write-tree" produced an incorrect tree
|
||||
when there are other paths in the same directory that sorts after
|
||||
"file".
|
||||
|
||||
* "git fetch http://user:pass@host/repo..." scrubbed the userinfo
|
||||
part, but "git push" didn't.
|
||||
|
||||
* "git merge" with renormalization did not work well with
|
||||
merge-recursive, due to "safer crlf" conversion kicking in when it
|
||||
shouldn't.
|
||||
(merge 1335d76 jc/renormalize-merge-kill-safer-crlf later to maint).
|
||||
|
||||
* The use of strbuf in "git rm" to build filename to remove was a bit
|
||||
suboptimal, which has been fixed.
|
||||
|
||||
* An age old bug that caused "git diff --ignore-space-at-eol"
|
||||
misbehave has been fixed.
|
||||
|
||||
* "git notes merge" had a code to see if a path exists (and fails if
|
||||
it does) and then open the path for writing (when it doesn't).
|
||||
Replace it with open with O_EXCL.
|
||||
|
||||
* "git pack-objects" and "git index-pack" mostly operate with off_t
|
||||
when talking about the offset of objects in a packfile, but there
|
||||
were a handful of places that used "unsigned long" to hold that
|
||||
value, leading to an unintended truncation.
|
||||
|
||||
* Recent update to "git daemon" tries to enable the socket-level
|
||||
KEEPALIVE, but when it is spawned via inetd, the standard input
|
||||
file descriptor may not necessarily be connected to a socket.
|
||||
Suppress an ENOTSOCK error from setsockopt().
|
||||
|
||||
* Recent FreeBSD stopped making perl available at /usr/bin/perl;
|
||||
switch the default the built-in path to /usr/local/bin/perl on not
|
||||
too ancient FreeBSD releases.
|
||||
|
||||
* "git commit --help" said "--no-verify" is only about skipping the
|
||||
pre-commit hook, and failed to say that it also skipped the
|
||||
commit-msg hook.
|
||||
|
||||
* "git merge" in Git v2.9 was taught to forbid merging an unrelated
|
||||
lines of history by default, but that is exactly the kind of thing
|
||||
the "--rejoin" mode of "git subtree" (in contrib/) wants to do.
|
||||
"git subtree" has been taught to use the "--allow-unrelated-histories"
|
||||
option to override the default.
|
||||
|
||||
* The build procedure for "git persistent-https" helper (in contrib/)
|
||||
has been updated so that it can be built with more recent versions
|
||||
of Go.
|
||||
|
||||
* There is an optimization used in "git diff $treeA $treeB" to borrow
|
||||
an already checked-out copy in the working tree when it is known to
|
||||
be the same as the blob being compared, expecting that open/mmap of
|
||||
such a file is faster than reading it from the object store, which
|
||||
involves inflating and applying delta. This however kicked in even
|
||||
when the checked-out copy needs to go through the convert-to-git
|
||||
conversion (including the clean filter), which defeats the whole
|
||||
point of the optimization. The optimization has been disabled when
|
||||
the conversion is necessary.
|
||||
|
||||
* "git -c grep.patternType=extended log --basic-regexp" misbehaved
|
||||
because the internal API to access the grep machinery was not
|
||||
designed well.
|
||||
|
||||
* Windows port was failing some tests in t4130, due to the lack of
|
||||
inum in the returned values by its lstat(2) emulation.
|
||||
|
||||
* The reflog output format is documented better, and a new format
|
||||
--date=unix to report the seconds-since-epoch (without timezone)
|
||||
has been added.
|
||||
(merge 442f6fd jk/reflog-date later to maint).
|
||||
|
||||
* "git difftool <paths>..." started in a subdirectory failed to
|
||||
interpret the paths relative to that directory, which has been
|
||||
fixed.
|
||||
|
||||
* The characters in the label shown for tags/refs for commits in
|
||||
"gitweb" output are now properly escaped for proper HTML output.
|
||||
|
||||
* FreeBSD can lie when asked mtime of a directory, which made the
|
||||
untracked cache code to fall back to a slow-path, which in turn
|
||||
caused tests in t7063 to fail because it wanted to verify the
|
||||
behaviour of the fast-path.
|
||||
|
||||
* Squelch compiler warnings for nedmalloc (in compat/) library.
|
||||
|
||||
* A small memory leak in the command line parsing of "git blame"
|
||||
has been plugged.
|
||||
|
||||
* The API documentation for hashmap was unclear if hashmap_entry
|
||||
can be safely discarded without any other consideration. State
|
||||
that it is safe to do so.
|
||||
|
||||
* Not-so-recent rewrite of "git am" that started making internal
|
||||
calls into the commit machinery had an unintended regression, in
|
||||
that no matter how many seconds it took to apply many patches, the
|
||||
resulting committer timestamp for the resulting commits were all
|
||||
the same.
|
||||
|
||||
* "git push --force-with-lease" already had enough logic to allow
|
||||
ensuring that such a push results in creation of a ref (i.e. the
|
||||
receiving end did not have another push from sideways that would be
|
||||
discarded by our force-pushing), but didn't expose this possibility
|
||||
to the users. It does so now.
|
||||
(merge 9eed4f3 jk/push-force-with-lease-creation later to maint).
|
||||
|
||||
* The mechanism to limit the pack window memory size, when packing is
|
||||
done using multiple threads (which is the default), is per-thread,
|
||||
but this was not documented clearly.
|
||||
(merge 954176c ms/document-pack-window-memory-is-per-thread later to maint).
|
||||
|
||||
* "import-tars" fast-import script (in contrib/) used to ignore a
|
||||
hardlink target and replaced it with an empty file, which has been
|
||||
corrected to record the same blob as the other file the hardlink is
|
||||
shared with.
|
||||
(merge 04e0869 js/import-tars-hardlinks later to maint).
|
||||
|
||||
* "git mv dir non-existing-dir/" did not work in some environments
|
||||
the same way as existing mainstream platforms. The code now moves
|
||||
"dir" to "non-existing-dir", without relying on rename("A", "B/")
|
||||
that strips the trailing slash of '/'.
|
||||
(merge 189d035 js/mv-dir-to-new-directory later to maint).
|
||||
|
||||
* The "t/" hierarchy is prone to get an unusual pathname; "make test"
|
||||
has been taught to make sure they do not contain paths that cannot
|
||||
be checked out on Windows (and the mechanism can be reusable to
|
||||
catch pathnames that are not portable to other platforms as need
|
||||
arises).
|
||||
(merge c2cafd3 js/test-lint-pathname later to maint).
|
||||
|
||||
* When "git merge-recursive" works on history with many criss-cross
|
||||
merges in "verbose" mode, the names the command assigns to the
|
||||
virtual merge bases could have overwritten each other by unintended
|
||||
reuse of the same piece of memory.
|
||||
(merge 5447a76 rs/pull-signed-tag later to maint).
|
||||
|
||||
* "git checkout --detach <branch>" used to give the same advice
|
||||
message as that is issued when "git checkout <tag>" (or anything
|
||||
that is not a branch name) is given, but asking with "--detach" is
|
||||
an explicit enough sign that the user knows what is going on. The
|
||||
advice message has been squelched in this case.
|
||||
(merge 779b88a sb/checkout-explit-detach-no-advice later to maint).
|
||||
|
||||
* "git difftool" by default ignores the error exit from the backend
|
||||
commands it spawns, because often they signal that they found
|
||||
differences by exiting with a non-zero status code just like "diff"
|
||||
does; the exit status codes 126 and above however are special in
|
||||
that they are used to signal that the command is not executable,
|
||||
does not exist, or killed by a signal. "git difftool" has been
|
||||
taught to notice these exit status codes.
|
||||
(merge 45a4f5d jk/difftool-command-not-found later to maint).
|
||||
|
||||
* On Windows, help.browser configuration variable used to be ignored,
|
||||
which has been corrected.
|
||||
(merge 6db5967 js/no-html-bypass-on-windows later to maint).
|
||||
|
||||
* The "git -c var[=val] cmd" facility to append a configuration
|
||||
variable definition at the end of the search order was described in
|
||||
git(1) manual page, but not in git-config(1), which was more likely
|
||||
place for people to look for when they ask "can I make a one-shot
|
||||
override, and if so how?"
|
||||
(merge ae1f709 dg/document-git-c-in-git-config-doc later to maint).
|
||||
|
||||
* The tempfile (hence its user lockfile) API lets the caller to open
|
||||
a file descriptor to a temporary file, write into it and then
|
||||
finalize it by first closing the filehandle and then either
|
||||
removing or renaming the temporary file. When the process spawns a
|
||||
subprocess after obtaining the file descriptor, and if the
|
||||
subprocess has not exited when the attempt to remove or rename is
|
||||
made, the last step fails on Windows, because the subprocess has
|
||||
the file descriptor still open. Open tempfile with O_CLOEXEC flag
|
||||
to avoid this (on Windows, this is mapped to O_NOINHERIT).
|
||||
(merge 05d1ed6 bw/mingw-avoid-inheriting-fd-to-lockfile later to maint).
|
||||
|
||||
* Correct an age-old calco (is that a typo-like word for calc)
|
||||
in the documentation.
|
||||
(merge 7841c48 ls/packet-line-protocol-doc-fix later to maint).
|
||||
|
||||
* Other minor clean-ups and documentation updates
|
||||
(merge 02a8cfa rs/merge-add-strategies-simplification later to maint).
|
||||
(merge af4941d rs/merge-recursive-string-list-init later to maint).
|
||||
(merge 1eb47f1 rs/use-strbuf-add-unique-abbrev later to maint).
|
||||
(merge ddd0bfa jk/tighten-alloc later to maint).
|
||||
(merge ecf30b2 rs/mailinfo-lib later to maint).
|
||||
(merge 0eb75ce sg/reflog-past-root later to maint).
|
||||
(merge 4369523 hv/doc-commit-reference-style later to maint).
|
|
@ -7,7 +7,7 @@ Fixes since v2.3.9
|
|||
* xdiff code we use to generate diffs is not prepared to handle
|
||||
extremely large files. It uses "int" in many places, which can
|
||||
overflow if we have a very large number of lines or even bytes in
|
||||
our input files, for example. Cap the input size to soemwhere
|
||||
our input files, for example. Cap the input size to somewhere
|
||||
around 1GB for now.
|
||||
|
||||
* Some protocols (like git-remote-ext) can execute arbitrary code
|
||||
|
|
|
@ -7,7 +7,7 @@ Fixes since v2.4.9
|
|||
* xdiff code we use to generate diffs is not prepared to handle
|
||||
extremely large files. It uses "int" in many places, which can
|
||||
overflow if we have a very large number of lines or even bytes in
|
||||
our input files, for example. Cap the input size to soemwhere
|
||||
our input files, for example. Cap the input size to somewhere
|
||||
around 1GB for now.
|
||||
|
||||
* Some protocols (like git-remote-ext) can execute arbitrary code
|
||||
|
|
|
@ -7,7 +7,7 @@ Fixes since v2.5.4
|
|||
* xdiff code we use to generate diffs is not prepared to handle
|
||||
extremely large files. It uses "int" in many places, which can
|
||||
overflow if we have a very large number of lines or even bytes in
|
||||
our input files, for example. Cap the input size to soemwhere
|
||||
our input files, for example. Cap the input size to somewhere
|
||||
around 1GB for now.
|
||||
|
||||
* Some protocols (like git-remote-ext) can execute arbitrary code
|
||||
|
|
|
@ -7,7 +7,7 @@ Fixes since v2.6
|
|||
* xdiff code we use to generate diffs is not prepared to handle
|
||||
extremely large files. It uses "int" in many places, which can
|
||||
overflow if we have a very large number of lines or even bytes in
|
||||
our input files, for example. Cap the input size to soemwhere
|
||||
our input files, for example. Cap the input size to somewhere
|
||||
around 1GB for now.
|
||||
|
||||
* Some protocols (like git-remote-ext) can execute arbitrary code
|
||||
|
|
|
@ -150,27 +150,34 @@ integer::
|
|||
1024", "by 1024x1024", etc.
|
||||
|
||||
color::
|
||||
The value for a variables that takes a color is a list of
|
||||
colors (at most two) and attributes (at most one), separated
|
||||
by spaces. The colors accepted are `normal`, `black`,
|
||||
`red`, `green`, `yellow`, `blue`, `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. Attributes may be turned off specifically
|
||||
by prefixing them with `no` (e.g., `noreverse`, `noul`, etc).
|
||||
The value for a variable that takes a color is a list of
|
||||
colors (at most two, one for foreground and one for background)
|
||||
and attributes (as many as you want), separated by spaces.
|
||||
+
|
||||
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). If your terminal supports it, you may also
|
||||
specify 24-bit RGB values as hex, like `#ff0ab3`.
|
||||
The basic colors accepted are `normal`, `black`, `red`, `green`, `yellow`,
|
||||
`blue`, `magenta`, `cyan` and `white`. The first color given is the
|
||||
foreground; the second is the background.
|
||||
+
|
||||
The attributes are meant to be reset at the beginning of each item
|
||||
in the colored output, so setting color.decorate.branch to `black`
|
||||
will paint that branch name in a plain `black`, even if the previous
|
||||
thing on the same output line (e.g. opening parenthesis before the
|
||||
list of branch names in `log --decorate` output) is set to be
|
||||
painted with `bold` or some other attribute.
|
||||
Colors 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). If
|
||||
your terminal supports it, you may also specify 24-bit RGB values as
|
||||
hex, like `#ff0ab3`.
|
||||
+
|
||||
The accepted attributes are `bold`, `dim`, `ul`, `blink`, `reverse`,
|
||||
`italic`, and `strike` (for crossed-out or "strikethrough" letters).
|
||||
The position of any attributes with respect to the colors
|
||||
(before, after, or in between), doesn't matter. Specific attributes may
|
||||
be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`,
|
||||
`no-ul`, etc).
|
||||
+
|
||||
For git's pre-defined color slots, the attributes are meant to be reset
|
||||
at the beginning of each item in the colored output. So setting
|
||||
`color.decorate.branch` to `black` will paint that branch name in a
|
||||
plain `black`, even if the previous thing on the same output line (e.g.
|
||||
opening parenthesis before the list of branch names in `log --decorate`
|
||||
output) is set to be painted with `bold` or some other attribute.
|
||||
However, custom log formats may do more complicated and layered
|
||||
coloring, and the negated forms may be useful there.
|
||||
|
||||
pathname::
|
||||
A variable that takes a pathname value can be given a
|
||||
|
@ -441,6 +448,13 @@ specify that no proxy be used for a given domain pattern.
|
|||
This is useful for excluding servers inside a firewall from
|
||||
proxy use, while defaulting to a common proxy for external domains.
|
||||
|
||||
core.sshCommand::
|
||||
If this variable is set, `git fetch` and `git push` will
|
||||
use the specified command instead of `ssh` when they need to
|
||||
connect to a remote system. The command is in the same form as
|
||||
the `GIT_SSH_COMMAND` environment variable and is overridden
|
||||
when the environment variable is set.
|
||||
|
||||
core.ignoreStat::
|
||||
If true, Git will avoid using lstat() calls to detect if files have
|
||||
changed by setting the "assume-unchanged" bit for those tracked files
|
||||
|
@ -1187,6 +1201,15 @@ difftool.<tool>.cmd::
|
|||
difftool.prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
|
||||
fastimport.unpackLimit::
|
||||
If the number of objects imported by linkgit:git-fast-import[1]
|
||||
is below this limit, then the objects will be unpacked into
|
||||
loose object files. However if the number of imported objects
|
||||
equals or exceeds this limit then the pack will be stored as a
|
||||
pack. Storing the pack from a fast-import can make the import
|
||||
operation complete faster, especially on slow filesystems. If
|
||||
not set, the value of `transfer.unpackLimit` is used instead.
|
||||
|
||||
fetch.recurseSubmodules::
|
||||
This option can be either set to a boolean value or to 'on-demand'.
|
||||
Setting it to a boolean changes the behavior of fetch and pull to
|
||||
|
@ -1218,6 +1241,11 @@ fetch.prune::
|
|||
If true, fetch will automatically behave as if the `--prune`
|
||||
option was given on the command line. See also `remote.<name>.prune`.
|
||||
|
||||
fetch.output::
|
||||
Control how ref update status is printed. Valid values are
|
||||
`full` and `compact`. Default value is `full`. See section
|
||||
OUTPUT in linkgit:git-fetch[1] for detail.
|
||||
|
||||
format.attach::
|
||||
Enable multipart/mixed attachments as the default for
|
||||
'format-patch'. The value can also be a double quoted string
|
||||
|
@ -1225,6 +1253,16 @@ format.attach::
|
|||
value as the boundary. See the --attach option in
|
||||
linkgit:git-format-patch[1].
|
||||
|
||||
format.from::
|
||||
Provides the default value for the `--from` option to format-patch.
|
||||
Accepts a boolean value, or a name and email address. If false,
|
||||
format-patch defaults to `--no-from`, using commit authors directly in
|
||||
the "From:" field of patch mails. If true, format-patch defaults to
|
||||
`--from`, using your committer identity in the "From:" field of patch
|
||||
mails and including a "From:" field in the body of the patch mail if
|
||||
different. If set to a non-boolean value, format-patch uses that
|
||||
value instead of your committer identity. Defaults to false.
|
||||
|
||||
format.numbered::
|
||||
A boolean which can enable or disable sequence numbers in patch
|
||||
subjects. It defaults to "auto" which enables it only if there
|
||||
|
@ -2399,8 +2437,13 @@ rebase.instructionFormat
|
|||
|
||||
receive.advertiseAtomic::
|
||||
By default, git-receive-pack will advertise the atomic push
|
||||
capability to its clients. If you don't want to this capability
|
||||
to be advertised, set this variable to false.
|
||||
capability to its clients. If you don't want to advertise this
|
||||
capability, set this variable to false.
|
||||
|
||||
receive.advertisePushOptions::
|
||||
By default, git-receive-pack will advertise the push options
|
||||
capability to its clients. If you don't want to advertise this
|
||||
capability, set this variable to false.
|
||||
|
||||
receive.autogc::
|
||||
By default, git-receive-pack will run "git-gc --auto" after
|
||||
|
@ -2455,6 +2498,15 @@ receive.fsck.skipList::
|
|||
can be safely ignored such as invalid committer email addresses.
|
||||
Note: corrupt objects cannot be skipped with this setting.
|
||||
|
||||
receive.keepAlive::
|
||||
After receiving the pack from the client, `receive-pack` may
|
||||
produce no output (if `--quiet` was specified) while processing
|
||||
the pack, causing some networks to drop the TCP connection.
|
||||
With this option set, if `receive-pack` does not transmit
|
||||
any data in this phase for `receive.keepAlive` seconds, it will
|
||||
send a short keepalive packet. The default is 5 seconds; set
|
||||
to 0 to disable keepalives entirely.
|
||||
|
||||
receive.unpackLimit::
|
||||
If the number of objects received in a push is below this
|
||||
limit then the objects will be unpacked into loose object
|
||||
|
@ -2881,6 +2933,21 @@ uploadpack.keepAlive::
|
|||
`uploadpack.keepAlive` seconds. Setting this option to 0
|
||||
disables keepalive packets entirely. The default is 5 seconds.
|
||||
|
||||
uploadpack.packObjectsHook::
|
||||
If this option is set, when `upload-pack` would run
|
||||
`git pack-objects` to create a packfile for a client, it will
|
||||
run this shell command instead. The `pack-objects` command and
|
||||
arguments it _would_ have run (including the `git pack-objects`
|
||||
at the beginning) are appended to the shell command. The stdin
|
||||
and stdout of the hook are treated as if `pack-objects` itself
|
||||
was run. I.e., `upload-pack` will feed input intended for
|
||||
`pack-objects` to the hook, and expects a completed packfile on
|
||||
stdout.
|
||||
+
|
||||
Note that this configuration variable is ignored if it is seen in the
|
||||
repository-level config (this is a safety measure against fetching from
|
||||
untrusted repositories).
|
||||
|
||||
url.<base>.insteadOf::
|
||||
Any URL that starts with this value will be rewritten to
|
||||
start, instead, with <base>. In cases where some site serves a
|
||||
|
|
|
@ -116,7 +116,8 @@ default. You can use `--no-utf8` to override this.
|
|||
By default the command will try to detect the patch format
|
||||
automatically. This option allows the user to bypass the automatic
|
||||
detection and specify the patch format that the patch(es) should be
|
||||
interpreted as. Valid formats are mbox, stgit, stgit-series and hg.
|
||||
interpreted as. Valid formats are mbox, mboxrd,
|
||||
stgit, stgit-series and hg.
|
||||
|
||||
-i::
|
||||
--interactive::
|
||||
|
|
|
@ -136,6 +136,8 @@ Performance and Compression Tuning
|
|||
Maximum size of each output packfile.
|
||||
The default is unlimited.
|
||||
|
||||
fastimport.unpackLimit::
|
||||
See linkgit:git-config[1]
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
|
|
@ -99,6 +99,57 @@ The latter use of the `remote.<repository>.fetch` values can be
|
|||
overridden by giving the `--refmap=<refspec>` parameter(s) on the
|
||||
command line.
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
|
||||
The output of "git fetch" depends on the transport method used; this
|
||||
section describes the output when fetching over the Git protocol
|
||||
(either locally or via ssh) and Smart HTTP protocol.
|
||||
|
||||
The status of the fetch is output in tabular form, with each line
|
||||
representing the status of a single ref. Each line is of the form:
|
||||
|
||||
-------------------------------
|
||||
<flag> <summary> <from> -> <to> [<reason>]
|
||||
-------------------------------
|
||||
|
||||
The status of up-to-date refs is shown only if the --verbose option is
|
||||
used.
|
||||
|
||||
In compact output mode, specified with configuration variable
|
||||
fetch.output, if either entire `<from>` or `<to>` is found in the
|
||||
other string, it will be substituted with `*` in the other string. For
|
||||
example, `master -> origin/master` becomes `master -> origin/*`.
|
||||
|
||||
flag::
|
||||
A single character indicating the status of the ref:
|
||||
(space);; for a successfully fetched fast-forward;
|
||||
`+`;; for a successful forced update;
|
||||
`-`;; for a successfully pruned ref;
|
||||
`t`;; for a successful tag update;
|
||||
`*`;; for a successfully fetched new ref;
|
||||
`!`;; for a ref that was rejected or failed to update; and
|
||||
`=`;; for a ref that was up to date and did not need fetching.
|
||||
|
||||
summary::
|
||||
For a successfully fetched ref, the summary shows the old and new
|
||||
values of the ref in a form suitable for using as an argument to
|
||||
`git log` (this is `<old>..<new>` in most cases, and
|
||||
`<old>...<new>` for forced non-fast-forward updates).
|
||||
|
||||
from::
|
||||
The name of the remote ref being fetched from, minus its
|
||||
`refs/<type>/` prefix. In the case of deletion, the name of
|
||||
the remote ref is "(none)".
|
||||
|
||||
to::
|
||||
The name of the local ref being updated, minus its
|
||||
`refs/<type>/` prefix.
|
||||
|
||||
reason::
|
||||
A human-readable explanation. In the case of successfully fetched
|
||||
refs, no explanation is needed. For a failed ref, the reason for
|
||||
failure is described.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
|
|
@ -11,7 +11,8 @@ SYNOPSIS
|
|||
[verse]
|
||||
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
|
||||
[--[no-]full] [--strict] [--verbose] [--lost-found]
|
||||
[--[no-]dangling] [--[no-]progress] [--connectivity-only] [<object>*]
|
||||
[--[no-]dangling] [--[no-]progress] [--connectivity-only]
|
||||
[--[no-]name-objects] [<object>*]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -82,6 +83,12 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
|
|||
a blob, the contents are written into the file, rather than
|
||||
its object name.
|
||||
|
||||
--name-objects::
|
||||
When displaying names of reachable objects, in addition to the
|
||||
SHA-1 also display a name that describes *how* they are reachable,
|
||||
compatible with linkgit:git-rev-parse[1], e.g.
|
||||
`HEAD@{1234567890}~25^2:src/`.
|
||||
|
||||
--[no-]progress::
|
||||
Progress status is reported on the standard error stream by
|
||||
default when it is attached to a terminal, unless
|
||||
|
|
|
@ -198,6 +198,10 @@ log.showRoot::
|
|||
`git log -p` output would be shown without a diff attached.
|
||||
The default is `true`.
|
||||
|
||||
log.showSignature::
|
||||
If `true`, `git log` and related commands will act as if the
|
||||
`--show-signature` option was passed to them.
|
||||
|
||||
mailmap.*::
|
||||
See linkgit:git-shortlog[1].
|
||||
|
||||
|
|
|
@ -159,8 +159,7 @@ not accessible in the working tree.
|
|||
+
|
||||
<eolattr> is the attribute that is used when checking out or committing,
|
||||
it is either "", "-text", "text", "text=auto", "text eol=lf", "text eol=crlf".
|
||||
Note: Currently Git does not support "text=auto eol=lf" or "text=auto eol=crlf",
|
||||
that may change in the future.
|
||||
Since Git 2.10 "text=auto eol=lf" and "text=auto eol=crlf" are supported.
|
||||
+
|
||||
Both the <eolinfo> in the index ("i/<eolinfo>")
|
||||
and in the working tree ("w/<eolinfo>") are shown for regular files,
|
||||
|
|
|
@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program
|
|||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] -o<directory> [--] [(<mbox>|<Maildir>)...]
|
||||
'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] [--mboxrd]
|
||||
-o<directory> [--] [(<mbox>|<Maildir>)...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -47,6 +48,10 @@ OPTIONS
|
|||
--keep-cr::
|
||||
Do not remove `\r` from lines ending with `\r\n`.
|
||||
|
||||
--mboxrd::
|
||||
Input is of the "mboxrd" format and "^>+From " line escaping is
|
||||
reversed.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[1] suite
|
||||
|
|
|
@ -11,7 +11,7 @@ SYNOPSIS
|
|||
[verse]
|
||||
'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
|
||||
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
|
||||
[-u | --set-upstream]
|
||||
[-u | --set-upstream] [--push-option=<string>]
|
||||
[--[no-]signed|--sign=(true|false|if-asked)]
|
||||
[--force-with-lease[=<refname>[:<expect>]]]
|
||||
[--no-verify] [<repository> [<refspec>...]]
|
||||
|
@ -156,6 +156,12 @@ already exists on the remote side.
|
|||
Either all refs are updated, or on error, no refs are updated.
|
||||
If the server does not support atomic pushes the push will fail.
|
||||
|
||||
-o::
|
||||
--push-option::
|
||||
Transmit the given string to the server, which passes them to
|
||||
the pre-receive as well as the post-receive hook. The given string
|
||||
must not contain a NUL or LF character.
|
||||
|
||||
--receive-pack=<git-receive-pack>::
|
||||
--exec=<git-receive-pack>::
|
||||
Path to the 'git-receive-pack' program on the remote
|
||||
|
|
|
@ -17,7 +17,7 @@ fetch, push or archive.
|
|||
|
||||
If only <infd> is given, it is assumed to be a bidirectional socket connected
|
||||
to remote Git server (git-upload-pack, git-receive-pack or
|
||||
git-upload-achive). If both <infd> and <outfd> are given, they are assumed
|
||||
git-upload-archive). If both <infd> and <outfd> are given, they are assumed
|
||||
to be pipes connected to a remote Git server (<infd> being the inbound pipe
|
||||
and <outfd> being the outbound pipe.
|
||||
|
||||
|
|
|
@ -130,6 +130,19 @@ other objects in that pack they already have locally.
|
|||
with `-b` or `repack.writeBitmaps`, as it ensures that the
|
||||
bitmapped packfile has the necessary objects.
|
||||
|
||||
--unpack-unreachable=<when>::
|
||||
When loosening unreachable objects, do not bother loosening any
|
||||
objects older than `<when>`. This can be used to optimize out
|
||||
the write of any objects that would be immediately pruned by
|
||||
a follow-up `git prune`.
|
||||
|
||||
-k::
|
||||
--keep-unreachable::
|
||||
When used with `-ad`, any unreachable objects from existing
|
||||
packs will be appended to the end of the packfile instead of
|
||||
being removed. In addition, any unreachable loose objects will
|
||||
be packed (and their loose counterparts removed).
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ SYNOPSIS
|
|||
'git submodule' [--quiet] init [--] [<path>...]
|
||||
'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)
|
||||
'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch]
|
||||
[-f|--force] [--rebase|--merge] [--reference <repository>]
|
||||
[--depth <depth>] [--recursive] [--jobs <n>] [--] [<path>...]
|
||||
[--[no-]recommend-shallow] [-f|--force] [--rebase|--merge]
|
||||
[--reference <repository>] [--depth <depth>] [--recursive]
|
||||
[--jobs <n>] [--] [<path>...]
|
||||
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
|
||||
[commit] [--] [<path>...]
|
||||
'git submodule' [--quiet] foreach [--recursive] <command>
|
||||
|
@ -384,6 +385,12 @@ for linkgit:git-clone[1]'s `--reference` and `--shared` options carefully.
|
|||
clone with a history truncated to the specified number of revisions.
|
||||
See linkgit:git-clone[1]
|
||||
|
||||
--[no-]recommend-shallow::
|
||||
This option is only valid for the update command.
|
||||
The initial clone of a submodule will use the recommended
|
||||
`submodule.<name>.shallow` as provided by the .gitmodules file
|
||||
by default. To ignore the suggestions use `--no-recommend-shallow`.
|
||||
|
||||
-j <n>::
|
||||
--jobs <n>::
|
||||
This option is only valid for the update command.
|
||||
|
|
|
@ -625,6 +625,9 @@ config key: svn.authorsfile
|
|||
with the committer name as the first argument. The program is
|
||||
expected to return a single line of the form "Name <email>",
|
||||
which will be treated as if included in the authors file.
|
||||
+
|
||||
[verse]
|
||||
config key: svn.authorsProg
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
|
|
|
@ -9,8 +9,8 @@ git-upload-pack - Send objects packed back to git-fetch-pack
|
|||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-upload-pack' [--strict] [--timeout=<n>] <directory>
|
||||
|
||||
'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]
|
||||
[--advertise-refs] <directory>
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Invoked by 'git fetch-pack', learns what
|
||||
|
@ -25,12 +25,22 @@ repository. For push operations, see 'git send-pack'.
|
|||
OPTIONS
|
||||
-------
|
||||
|
||||
--strict::
|
||||
--[no-]strict::
|
||||
Do not try <directory>/.git/ if <directory> is no Git directory.
|
||||
|
||||
--timeout=<n>::
|
||||
Interrupt transfer after <n> seconds of inactivity.
|
||||
|
||||
--stateless-rpc::
|
||||
Perform only a single read-write cycle with stdin and stdout.
|
||||
This fits with the HTTP POST request processing model where
|
||||
a program may read the request, write a response, and must exit.
|
||||
|
||||
--advertise-refs::
|
||||
Only the initial ref advertisement is output, and the program exits
|
||||
immediately. This fits with the HTTP GET request model, where
|
||||
no request content is received but a response must be produced.
|
||||
|
||||
<directory>::
|
||||
The repository to sync from.
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@ SYNOPSIS
|
|||
--------
|
||||
[verse]
|
||||
'git worktree add' [-f] [--detach] [--checkout] [-b <new-branch>] <path> [<branch>]
|
||||
'git worktree prune' [-n] [-v] [--expire <expire>]
|
||||
'git worktree list' [--porcelain]
|
||||
'git worktree lock' [--reason <string>] <worktree>
|
||||
'git worktree prune' [-n] [-v] [--expire <expire>]
|
||||
'git worktree unlock' <worktree>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -38,9 +40,8 @@ section "DETAILS" for more information.
|
|||
|
||||
If a linked working tree is stored on a portable device or network share
|
||||
which is not always mounted, you can prevent its administrative files from
|
||||
being pruned by creating a file named 'locked' alongside the other
|
||||
administrative files, optionally containing a plain text reason that
|
||||
pruning should be suppressed. See section "DETAILS" for more information.
|
||||
being pruned by issuing the `git worktree lock` command, optionally
|
||||
specifying `--reason` to explain why the working tree is locked.
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
|
@ -48,16 +49,13 @@ add <path> [<branch>]::
|
|||
|
||||
Create `<path>` and checkout `<branch>` into it. The new working directory
|
||||
is linked to the current repository, sharing everything except working
|
||||
directory specific files such as HEAD, index, etc.
|
||||
directory specific files such as HEAD, index, etc. `-` may also be
|
||||
specified as `<branch>`; it is synonymous with `@{-1}`.
|
||||
+
|
||||
If `<branch>` is omitted and neither `-b` nor `-B` nor `--detached` used,
|
||||
then, as a convenience, a new branch based at HEAD is created automatically,
|
||||
as if `-b $(basename <path>)` was specified.
|
||||
|
||||
prune::
|
||||
|
||||
Prune working tree information in $GIT_DIR/worktrees.
|
||||
|
||||
list::
|
||||
|
||||
List details of each worktree. The main worktree is listed first, followed by
|
||||
|
@ -65,6 +63,22 @@ each of the linked worktrees. The output details include if the worktree is
|
|||
bare, the revision currently checked out, and the branch currently checked out
|
||||
(or 'detached HEAD' if none).
|
||||
|
||||
lock::
|
||||
|
||||
If a working tree is on a portable device or network share which
|
||||
is not always mounted, lock it to prevent its administrative
|
||||
files from being pruned automatically. This also prevents it from
|
||||
being moved or deleted. Optionally, specify a reason for the lock
|
||||
with `--reason`.
|
||||
|
||||
prune::
|
||||
|
||||
Prune working tree information in $GIT_DIR/worktrees.
|
||||
|
||||
unlock::
|
||||
|
||||
Unlock a working tree, allowing it to be pruned, moved or deleted.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
|
@ -110,6 +124,18 @@ OPTIONS
|
|||
--expire <time>::
|
||||
With `prune`, only expire unused working trees older than <time>.
|
||||
|
||||
--reason <string>::
|
||||
With `lock`, an explanation why the working tree is locked.
|
||||
|
||||
<worktree>::
|
||||
Working trees can be identified by path, either relative or
|
||||
absolute.
|
||||
+
|
||||
If the last path components in the working tree's path is unique among
|
||||
working trees, it can be used to identify worktrees. For example if
|
||||
you only have to working trees at "/abc/def/ghi" and "/abc/def/ggg",
|
||||
then "ghi" or "def/ghi" is enough to point to the former working tree.
|
||||
|
||||
DETAILS
|
||||
-------
|
||||
Each linked working tree has a private sub-directory in the repository's
|
||||
|
@ -150,7 +176,8 @@ instead.
|
|||
|
||||
To prevent a $GIT_DIR/worktrees entry from being pruned (which
|
||||
can be useful in some situations, such as when the
|
||||
entry's working tree is stored on a portable device), add a file named
|
||||
entry's working tree is stored on a portable device), use the
|
||||
`git worktree lock` command, which adds a file named
|
||||
'locked' to the entry's directory. The file contains the reason in
|
||||
plain text. For example, if a linked working tree's `.git` file points
|
||||
to `/path/main/.git/worktrees/test-next` then a file named
|
||||
|
@ -226,8 +253,6 @@ performed manually, such as:
|
|||
- `remove` to remove a linked working tree and its administrative files (and
|
||||
warn if the working tree is dirty)
|
||||
- `mv` to move or rename a working tree and update its administrative files
|
||||
- `lock` to prevent automatic pruning of administrative files (for instance,
|
||||
for a working tree on a portable device)
|
||||
|
||||
GIT
|
||||
---
|
||||
|
|
|
@ -43,6 +43,11 @@ unreleased) version of Git, that is available from the 'master'
|
|||
branch of the `git.git` repository.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v2.10.0/git.html[documentation for release 2.10]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes/2.10.0.txt[2.10].
|
||||
|
||||
* link:v2.9.3/git.html[documentation for release 2.9.3]
|
||||
|
||||
* release notes for
|
||||
|
@ -1086,6 +1091,14 @@ of clones and fetches.
|
|||
cloning of shallow repositories.
|
||||
See `GIT_TRACE` for available trace output options.
|
||||
|
||||
`GIT_TRACE_CURL`::
|
||||
Enables a curl full trace dump of all incoming and outgoing data,
|
||||
including descriptive information, of the git transport protocol.
|
||||
This is similar to doing curl `--trace-ascii` on the command line.
|
||||
This option overrides setting the `GIT_CURL_VERBOSE` environment
|
||||
variable.
|
||||
See `GIT_TRACE` for available trace output options.
|
||||
|
||||
`GIT_LITERAL_PATHSPECS`::
|
||||
Setting this variable to `1` will cause Git to treat all
|
||||
pathspecs literally, rather than as glob patterns. For example,
|
||||
|
|
|
@ -133,7 +133,7 @@ Set to string value "auto"::
|
|||
When `text` is set to "auto", the path is marked for automatic
|
||||
end-of-line conversion. If Git decides that the content is
|
||||
text, its line endings are converted to LF on checkin.
|
||||
When the file has been commited with CRLF, no conversion is done.
|
||||
When the file has been committed with CRLF, no conversion is done.
|
||||
|
||||
Unspecified::
|
||||
|
||||
|
@ -182,6 +182,30 @@ While Git normally leaves file contents alone, it can be configured to
|
|||
normalize line endings to LF in the repository and, optionally, to
|
||||
convert them to CRLF when files are checked out.
|
||||
|
||||
If you simply want to have CRLF line endings in your working directory
|
||||
regardless of the repository you are working with, you can set the
|
||||
config variable "core.autocrlf" without using any attributes.
|
||||
|
||||
------------------------
|
||||
[core]
|
||||
autocrlf = true
|
||||
------------------------
|
||||
|
||||
This does not force normalization of text files, but does ensure
|
||||
that text files that you introduce to the repository have their line
|
||||
endings normalized to LF when they are added, and that files that are
|
||||
already normalized in the repository stay normalized.
|
||||
|
||||
If you want to ensure that text files that any contributor introduces to
|
||||
the repository have their line endings normalized, you can set the
|
||||
`text` attribute to "auto" for _all_ files.
|
||||
|
||||
------------------------
|
||||
* text=auto
|
||||
------------------------
|
||||
|
||||
The attributes allow a fine-grained control, how the line endings
|
||||
are converted.
|
||||
Here is an example that will make Git normalize .txt, .vcproj and .sh
|
||||
files, ensure that .vcproj files have CRLF and .sh files have LF in
|
||||
the working directory, and prevent .jpg files from being normalized
|
||||
|
@ -195,48 +219,14 @@ regardless of their content.
|
|||
*.jpg -text
|
||||
------------------------
|
||||
|
||||
Other source code management systems normalize all text files in their
|
||||
repositories, and there are two ways to enable similar automatic
|
||||
normalization in Git.
|
||||
NOTE: When `text=auto` conversion is enabled in a cross-platform
|
||||
project using push and pull to a central repository the text files
|
||||
containing CRLFs should be normalized.
|
||||
|
||||
If you simply want to have CRLF line endings in your working directory
|
||||
regardless of the repository you are working with, you can set the
|
||||
config variable "core.autocrlf" without using any attributes.
|
||||
|
||||
------------------------
|
||||
[core]
|
||||
autocrlf = true
|
||||
------------------------
|
||||
|
||||
This does not force normalization of all text files, but does ensure
|
||||
that text files that you introduce to the repository have their line
|
||||
endings normalized to LF when they are added, and that files that are
|
||||
already normalized in the repository stay normalized.
|
||||
|
||||
If you want to interoperate with a source code management system that
|
||||
enforces end-of-line normalization, or you simply want all text files
|
||||
in your repository to be normalized, you should instead set the `text`
|
||||
attribute to "auto" for _all_ files.
|
||||
|
||||
------------------------
|
||||
* text=auto
|
||||
------------------------
|
||||
|
||||
This ensures that all files that Git considers to be text will have
|
||||
normalized (LF) line endings in the repository. The `core.eol`
|
||||
configuration variable controls which line endings Git will use for
|
||||
normalized files in your working directory; the default is to use the
|
||||
native line ending for your platform, or CRLF if `core.autocrlf` is
|
||||
set.
|
||||
|
||||
NOTE: When `text=auto` normalization is enabled in an existing
|
||||
repository, any text files containing CRLFs should be normalized. If
|
||||
they are not they will be normalized the next time someone tries to
|
||||
change them, causing unfortunate misattribution. From a clean working
|
||||
directory:
|
||||
From a clean working directory:
|
||||
|
||||
-------------------------------------------------
|
||||
$ echo "* text=auto" >>.gitattributes
|
||||
$ echo "* text=auto" >.gitattributes
|
||||
$ rm .git/index # Remove the index to force Git to
|
||||
$ git reset # re-scan the working directory
|
||||
$ git status # Show files that will be normalized
|
||||
|
@ -533,6 +523,8 @@ patterns are available:
|
|||
|
||||
- `csharp` suitable for source code in the C# language.
|
||||
|
||||
- `css` suitable for cascading style sheets.
|
||||
|
||||
- `fortran` suitable for source code in the Fortran language.
|
||||
|
||||
- `fountain` suitable for Fountain documents.
|
||||
|
|
|
@ -247,6 +247,15 @@ Both standard output and standard error output are forwarded to
|
|||
'git send-pack' on the other end, so you can simply `echo` messages
|
||||
for the user.
|
||||
|
||||
The number of push options given on the command line of
|
||||
`git push --push-option=...` can be read from the environment
|
||||
variable `GIT_PUSH_OPTION_COUNT`, and the options themselves are
|
||||
found in `GIT_PUSH_OPTION_0`, `GIT_PUSH_OPTION_1`,...
|
||||
If it is negotiated to not use the push options phase, the
|
||||
environment variables will not be set. If the client selects
|
||||
to use push options, but doesn't transmit any, the count variable
|
||||
will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
|
||||
|
||||
[[update]]
|
||||
update
|
||||
~~~~~~
|
||||
|
@ -322,6 +331,15 @@ a sample script `post-receive-email` provided in the `contrib/hooks`
|
|||
directory in Git distribution, which implements sending commit
|
||||
emails.
|
||||
|
||||
The number of push options given on the command line of
|
||||
`git push --push-option=...` can be read from the environment
|
||||
variable `GIT_PUSH_OPTION_COUNT`, and the options themselves are
|
||||
found in `GIT_PUSH_OPTION_0`, `GIT_PUSH_OPTION_1`,...
|
||||
If it is negotiated to not use the push options phase, the
|
||||
environment variables will not be set. If the client selects
|
||||
to use push options, but doesn't transmit any, the count variable
|
||||
will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
|
||||
|
||||
[[post-update]]
|
||||
post-update
|
||||
~~~~~~~~~~~
|
||||
|
|
|
@ -79,6 +79,11 @@ submodule.<name>.ignore::
|
|||
"--ignore-submodule" option. The 'git submodule' commands are not
|
||||
affected by this setting.
|
||||
|
||||
submodule.<name>.shallow::
|
||||
When set to true, a clone of this submodule will be performed as a
|
||||
shallow clone unless the user explicitly asks for a non-shallow
|
||||
clone.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
|
|
@ -289,6 +289,10 @@ ifdef::git-rev-list[]
|
|||
Try to speed up the traversal using the pack bitmap index (if
|
||||
one is available). Note that when traversing with `--objects`,
|
||||
trees and blobs will not have their associated path printed.
|
||||
|
||||
--progress=<header>::
|
||||
Show progress reports on stderr as objects are considered. The
|
||||
`<header>` text will be printed with each progress update.
|
||||
endif::git-rev-list[]
|
||||
|
||||
--
|
||||
|
|
|
@ -454,7 +454,8 @@ The reference discovery phase is done nearly the same way as it is in the
|
|||
fetching protocol. Each reference obj-id and name on the server is sent
|
||||
in packet-line format to the client, followed by a flush-pkt. The only
|
||||
real difference is that the capability listing is different - the only
|
||||
possible values are 'report-status', 'delete-refs' and 'ofs-delta'.
|
||||
possible values are 'report-status', 'delete-refs', 'ofs-delta' and
|
||||
'push-options'.
|
||||
|
||||
Reference Update Request and Packfile Transfer
|
||||
----------------------------------------------
|
||||
|
@ -465,9 +466,10 @@ that it wants to update, it sends a line listing the obj-id currently on
|
|||
the server, the obj-id the client would like to update it to and the name
|
||||
of the reference.
|
||||
|
||||
This list is followed by a flush-pkt and then the packfile that should
|
||||
contain all the objects that the server will need to complete the new
|
||||
references.
|
||||
This list is followed by a flush-pkt. Then the push options are transmitted
|
||||
one per packet followed by another flush-pkt. After that the packfile that
|
||||
should contain all the objects that the server will need to complete the new
|
||||
references will be sent.
|
||||
|
||||
----
|
||||
update-request = *shallow ( command-list | push-cert ) [packfile]
|
||||
|
|
|
@ -253,6 +253,15 @@ atomic pushes. If the pushing client requests this capability, the server
|
|||
will update the refs in one atomic transaction. Either all refs are
|
||||
updated or none.
|
||||
|
||||
push-options
|
||||
------------
|
||||
|
||||
If the server sends the 'push-options' capability it is able to accept
|
||||
push options after the update commands have been sent, but before the
|
||||
packfile is streamed. If the pushing client requests this capability,
|
||||
the server will pass the options to the pre- and post- receive hooks
|
||||
that process this push request.
|
||||
|
||||
allow-tip-sha1-in-want
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v2.9.3
|
||||
DEF_VER=v2.10.0
|
||||
|
||||
LF='
|
||||
'
|
||||
|
|
41
Makefile
41
Makefile
|
@ -351,9 +351,12 @@ all::
|
|||
# Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not
|
||||
# return NULL when it receives a bogus time_t.
|
||||
#
|
||||
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
|
||||
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime.
|
||||
#
|
||||
# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC in librt.
|
||||
# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC.
|
||||
#
|
||||
# Define NEEDS_LIBRT if your platform requires linking with librt (glibc version
|
||||
# before 2.17) for clock_gettime and CLOCK_MONOTONIC.
|
||||
#
|
||||
# Define USE_PARENS_AROUND_GETTEXT_N to "yes" if your compiler happily
|
||||
# compiles the following initialization:
|
||||
|
@ -367,6 +370,14 @@ all::
|
|||
# Define HAVE_BSD_SYSCTL if your platform has a BSD-compatible sysctl function.
|
||||
#
|
||||
# Define HAVE_GETDELIM if your system has the getdelim() function.
|
||||
#
|
||||
# Define PAGER_ENV to a SP separated VAR=VAL pairs to define
|
||||
# default environment variables to be passed when a pager is spawned, e.g.
|
||||
#
|
||||
# PAGER_ENV = LESS=FRX LV=-c
|
||||
#
|
||||
# to say "export LESS=FRX (and LV=-c) if the environment variable
|
||||
# LESS (and LV) is not set, respectively".
|
||||
|
||||
GIT-VERSION-FILE: FORCE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
|
@ -718,6 +729,7 @@ LIB_OBJS += diff-lib.o
|
|||
LIB_OBJS += diff-no-index.o
|
||||
LIB_OBJS += diff.o
|
||||
LIB_OBJS += dir.o
|
||||
LIB_OBJS += dir-iterator.o
|
||||
LIB_OBJS += editor.o
|
||||
LIB_OBJS += entry.o
|
||||
LIB_OBJS += environment.o
|
||||
|
@ -751,6 +763,7 @@ LIB_OBJS += merge.o
|
|||
LIB_OBJS += merge-blobs.o
|
||||
LIB_OBJS += merge-recursive.o
|
||||
LIB_OBJS += mergesort.o
|
||||
LIB_OBJS += mru.o
|
||||
LIB_OBJS += name-hash.o
|
||||
LIB_OBJS += notes.o
|
||||
LIB_OBJS += notes-cache.o
|
||||
|
@ -782,6 +795,7 @@ LIB_OBJS += read-cache.o
|
|||
LIB_OBJS += reflog-walk.o
|
||||
LIB_OBJS += refs.o
|
||||
LIB_OBJS += refs/files-backend.o
|
||||
LIB_OBJS += refs/iterator.o
|
||||
LIB_OBJS += ref-filter.o
|
||||
LIB_OBJS += remote.o
|
||||
LIB_OBJS += replace_object.o
|
||||
|
@ -1465,13 +1479,16 @@ endif
|
|||
|
||||
ifdef HAVE_CLOCK_GETTIME
|
||||
BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
|
||||
EXTLIBS += -lrt
|
||||
endif
|
||||
|
||||
ifdef HAVE_CLOCK_MONOTONIC
|
||||
BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
|
||||
endif
|
||||
|
||||
ifdef NEEDS_LIBRT
|
||||
EXTLIBS += -lrt
|
||||
endif
|
||||
|
||||
ifdef HAVE_BSD_SYSCTL
|
||||
BASIC_CFLAGS += -DHAVE_BSD_SYSCTL
|
||||
endif
|
||||
|
@ -1492,6 +1509,10 @@ ifeq ($(PYTHON_PATH),)
|
|||
NO_PYTHON = NoThanks
|
||||
endif
|
||||
|
||||
ifndef PAGER_ENV
|
||||
PAGER_ENV = LESS=FRX LV=-c
|
||||
endif
|
||||
|
||||
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
|
||||
QUIET_SUBDIR1 =
|
||||
|
||||
|
@ -1621,6 +1642,11 @@ ifdef DEFAULT_HELP_FORMAT
|
|||
BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
|
||||
endif
|
||||
|
||||
PAGER_ENV_SQ = $(subst ','\'',$(PAGER_ENV))
|
||||
PAGER_ENV_CQ = "$(subst ",\",$(subst \,\\,$(PAGER_ENV)))"
|
||||
PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ))
|
||||
BASIC_CFLAGS += -DPAGER_ENV='$(PAGER_ENV_CQ_SQ)'
|
||||
|
||||
ALL_CFLAGS += $(BASIC_CFLAGS)
|
||||
ALL_LDFLAGS += $(BASIC_LDFLAGS)
|
||||
|
||||
|
@ -1745,7 +1771,7 @@ common-cmds.h: $(wildcard Documentation/git-*.txt)
|
|||
|
||||
SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
|
||||
$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
|
||||
$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP)
|
||||
$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV)
|
||||
define cmd_munge_script
|
||||
$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
|
@ -1758,6 +1784,7 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
|||
-e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
-e 's|@@SANE_TEXT_GREP@@|$(SANE_TEXT_GREP)|g' \
|
||||
-e 's|@@PAGER_ENV@@|$(PAGER_ENV_SQ)|g' \
|
||||
$@.sh >$@+
|
||||
endef
|
||||
|
||||
|
@ -2072,7 +2099,10 @@ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
|
|||
--keyword=gettextln --keyword=eval_gettextln
|
||||
XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
|
||||
LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
|
||||
LOCALIZED_SH = $(SCRIPT_SH) git-parse-remote.sh
|
||||
LOCALIZED_SH = $(SCRIPT_SH)
|
||||
LOCALIZED_SH += git-parse-remote.sh
|
||||
LOCALIZED_SH += git-rebase--interactive.sh
|
||||
LOCALIZED_SH += git-sh-setup.sh
|
||||
LOCALIZED_PERL = $(SCRIPT_PERL)
|
||||
|
||||
ifdef XGETTEXT_INCLUDE_TESTS
|
||||
|
@ -2162,6 +2192,7 @@ GIT-BUILD-OPTIONS: FORCE
|
|||
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
|
||||
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+
|
||||
@echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
|
||||
@echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
|
||||
ifdef TEST_OUTPUT_DIRECTORY
|
||||
@echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
|
||||
endif
|
||||
|
|
2
RelNotes
2
RelNotes
|
@ -1 +1 @@
|
|||
Documentation/RelNotes/2.9.4.txt
|
||||
Documentation/RelNotes/2.10.0.txt
|
23
advice.c
23
advice.c
|
@ -79,7 +79,20 @@ int git_default_advice_config(const char *var, const char *value)
|
|||
|
||||
int error_resolve_conflict(const char *me)
|
||||
{
|
||||
error("%s is not possible because you have unmerged files.", me);
|
||||
if (!strcmp(me, "cherry-pick"))
|
||||
error(_("Cherry-picking is not possible because you have unmerged files."));
|
||||
else if (!strcmp(me, "commit"))
|
||||
error(_("Committing is not possible because you have unmerged files."));
|
||||
else if (!strcmp(me, "merge"))
|
||||
error(_("Merging is not possible because you have unmerged files."));
|
||||
else if (!strcmp(me, "pull"))
|
||||
error(_("Pulling is not possible because you have unmerged files."));
|
||||
else if (!strcmp(me, "revert"))
|
||||
error(_("Reverting is not possible because you have unmerged files."));
|
||||
else
|
||||
error(_("It is not possible to %s because you have unmerged files."),
|
||||
me);
|
||||
|
||||
if (advice_resolve_conflict)
|
||||
/*
|
||||
* Message used both when 'git commit' fails and when
|
||||
|
@ -93,7 +106,7 @@ int error_resolve_conflict(const char *me)
|
|||
void NORETURN die_resolve_conflict(const char *me)
|
||||
{
|
||||
error_resolve_conflict(me);
|
||||
die("Exiting because of an unresolved conflict.");
|
||||
die(_("Exiting because of an unresolved conflict."));
|
||||
}
|
||||
|
||||
void NORETURN die_conclude_merge(void)
|
||||
|
@ -106,14 +119,14 @@ void NORETURN die_conclude_merge(void)
|
|||
|
||||
void detach_advice(const char *new_name)
|
||||
{
|
||||
const char fmt[] =
|
||||
"Note: checking out '%s'.\n\n"
|
||||
const char *fmt =
|
||||
_("Note: checking out '%s'.\n\n"
|
||||
"You are in 'detached HEAD' state. You can look around, make experimental\n"
|
||||
"changes and commit them, and you can discard any commits you make in this\n"
|
||||
"state without impacting any branches by performing another checkout.\n\n"
|
||||
"If you want to create a new branch to retain commits you create, you may\n"
|
||||
"do so (now or later) by using -b with the checkout command again. Example:\n\n"
|
||||
" git checkout -b <new-branch-name>\n\n";
|
||||
" git checkout -b <new-branch-name>\n\n");
|
||||
|
||||
fprintf(stderr, fmt, new_name);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,21 @@ static int tar_umask = 002;
|
|||
static int write_tar_filter_archive(const struct archiver *ar,
|
||||
struct archiver_args *args);
|
||||
|
||||
/*
|
||||
* This is the max value that a ustar size header can specify, as it is fixed
|
||||
* at 11 octal digits. POSIX specifies that we switch to extended headers at
|
||||
* this size.
|
||||
*
|
||||
* Likewise for the mtime (which happens to use a buffer of the same size).
|
||||
*/
|
||||
#if ULONG_MAX == 0xFFFFFFFF
|
||||
#define USTAR_MAX_SIZE ULONG_MAX
|
||||
#define USTAR_MAX_MTIME ULONG_MAX
|
||||
#else
|
||||
#define USTAR_MAX_SIZE 077777777777UL
|
||||
#define USTAR_MAX_MTIME 077777777777UL
|
||||
#endif
|
||||
|
||||
/* writes out the whole block, but only if it is full */
|
||||
static void write_if_needed(void)
|
||||
{
|
||||
|
@ -137,6 +152,20 @@ static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
|
|||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Like strbuf_append_ext_header, but for numeric values.
|
||||
*/
|
||||
static void strbuf_append_ext_header_uint(struct strbuf *sb,
|
||||
const char *keyword,
|
||||
uintmax_t value)
|
||||
{
|
||||
char buf[40]; /* big enough for 2^128 in decimal, plus NUL */
|
||||
int len;
|
||||
|
||||
len = xsnprintf(buf, sizeof(buf), "%"PRIuMAX, value);
|
||||
strbuf_append_ext_header(sb, keyword, buf, len);
|
||||
}
|
||||
|
||||
static unsigned int ustar_header_chksum(const struct ustar_header *header)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)header;
|
||||
|
@ -184,9 +213,9 @@ static void prepare_header(struct archiver_args *args,
|
|||
xsnprintf(header->chksum, sizeof(header->chksum), "%07o", ustar_header_chksum(header));
|
||||
}
|
||||
|
||||
static int write_extended_header(struct archiver_args *args,
|
||||
const unsigned char *sha1,
|
||||
const void *buffer, unsigned long size)
|
||||
static void write_extended_header(struct archiver_args *args,
|
||||
const unsigned char *sha1,
|
||||
const void *buffer, unsigned long size)
|
||||
{
|
||||
struct ustar_header header;
|
||||
unsigned int mode;
|
||||
|
@ -197,7 +226,6 @@ static int write_extended_header(struct archiver_args *args,
|
|||
prepare_header(args, &header, mode, size);
|
||||
write_blocked(&header, sizeof(header));
|
||||
write_blocked(buffer, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_tar_entry(struct archiver_args *args,
|
||||
|
@ -208,7 +236,7 @@ static int write_tar_entry(struct archiver_args *args,
|
|||
struct ustar_header header;
|
||||
struct strbuf ext_header = STRBUF_INIT;
|
||||
unsigned int old_mode = mode;
|
||||
unsigned long size;
|
||||
unsigned long size, size_in_header;
|
||||
void *buffer;
|
||||
int err = 0;
|
||||
|
||||
|
@ -267,15 +295,17 @@ static int write_tar_entry(struct archiver_args *args,
|
|||
memcpy(header.linkname, buffer, size);
|
||||
}
|
||||
|
||||
prepare_header(args, &header, mode, size);
|
||||
size_in_header = size;
|
||||
if (S_ISREG(mode) && size > USTAR_MAX_SIZE) {
|
||||
size_in_header = 0;
|
||||
strbuf_append_ext_header_uint(&ext_header, "size", size);
|
||||
}
|
||||
|
||||
prepare_header(args, &header, mode, size_in_header);
|
||||
|
||||
if (ext_header.len > 0) {
|
||||
err = write_extended_header(args, sha1, ext_header.buf,
|
||||
ext_header.len);
|
||||
if (err) {
|
||||
free(buffer);
|
||||
return err;
|
||||
}
|
||||
write_extended_header(args, sha1, ext_header.buf,
|
||||
ext_header.len);
|
||||
}
|
||||
strbuf_release(&ext_header);
|
||||
write_blocked(&header, sizeof(header));
|
||||
|
@ -289,15 +319,25 @@ static int write_tar_entry(struct archiver_args *args,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int write_global_extended_header(struct archiver_args *args)
|
||||
static void write_global_extended_header(struct archiver_args *args)
|
||||
{
|
||||
const unsigned char *sha1 = args->commit_sha1;
|
||||
struct strbuf ext_header = STRBUF_INIT;
|
||||
struct ustar_header header;
|
||||
unsigned int mode;
|
||||
int err = 0;
|
||||
|
||||
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
|
||||
if (sha1)
|
||||
strbuf_append_ext_header(&ext_header, "comment",
|
||||
sha1_to_hex(sha1), 40);
|
||||
if (args->time > USTAR_MAX_MTIME) {
|
||||
strbuf_append_ext_header_uint(&ext_header, "mtime",
|
||||
args->time);
|
||||
args->time = USTAR_MAX_MTIME;
|
||||
}
|
||||
|
||||
if (!ext_header.len)
|
||||
return;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
|
||||
mode = 0100666;
|
||||
|
@ -306,7 +346,6 @@ static int write_global_extended_header(struct archiver_args *args)
|
|||
write_blocked(&header, sizeof(header));
|
||||
write_blocked(ext_header.buf, ext_header.len);
|
||||
strbuf_release(&ext_header);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct archiver **tar_filters;
|
||||
|
@ -382,10 +421,8 @@ static int write_tar_archive(const struct archiver *ar,
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
if (args->commit_sha1)
|
||||
err = write_global_extended_header(args);
|
||||
if (!err)
|
||||
err = write_archive_entries(args, write_tar_entry);
|
||||
write_global_extended_header(args);
|
||||
err = write_archive_entries(args, write_tar_entry);
|
||||
if (!err)
|
||||
write_trailer();
|
||||
return err;
|
||||
|
|
12
archive.c
12
archive.c
|
@ -322,7 +322,7 @@ static int path_exists(struct tree *tree, const char *path)
|
|||
pathspec.recursive = 1;
|
||||
ret = read_tree_recursive(tree, "", 0, 0, &pathspec,
|
||||
reject_entry, &pathspec);
|
||||
free_pathspec(&pathspec);
|
||||
clear_pathspec(&pathspec);
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
|
@ -458,11 +458,11 @@ static int parse_archive_args(int argc, const char **argv,
|
|||
argc = parse_options(argc, argv, NULL, opts, archive_usage, 0);
|
||||
|
||||
if (remote)
|
||||
die("Unexpected option --remote");
|
||||
die(_("Unexpected option --remote"));
|
||||
if (exec)
|
||||
die("Option --exec can only be used together with --remote");
|
||||
die(_("Option --exec can only be used together with --remote"));
|
||||
if (output)
|
||||
die("Unexpected option --output");
|
||||
die(_("Unexpected option --output"));
|
||||
|
||||
if (!base)
|
||||
base = "";
|
||||
|
@ -484,14 +484,14 @@ static int parse_archive_args(int argc, const char **argv,
|
|||
usage_with_options(archive_usage, opts);
|
||||
*ar = lookup_archiver(format);
|
||||
if (!*ar || (is_remote && !((*ar)->flags & ARCHIVER_REMOTE)))
|
||||
die("Unknown archive format '%s'", format);
|
||||
die(_("Unknown archive format '%s'"), format);
|
||||
|
||||
args->compression_level = Z_DEFAULT_COMPRESSION;
|
||||
if (compression_level != -1) {
|
||||
if ((*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS)
|
||||
args->compression_level = compression_level;
|
||||
else {
|
||||
die("Argument not supported for format '%s': -%d",
|
||||
die(_("Argument not supported for format '%s': -%d"),
|
||||
format, compression_level);
|
||||
}
|
||||
}
|
||||
|
|
63
bisect.c
63
bisect.c
|
@ -438,12 +438,12 @@ static void read_bisect_paths(struct argv_array *array)
|
|||
FILE *fp = fopen(filename, "r");
|
||||
|
||||
if (!fp)
|
||||
die_errno("Could not open file '%s'", filename);
|
||||
die_errno(_("Could not open file '%s'"), filename);
|
||||
|
||||
while (strbuf_getline_lf(&str, fp) != EOF) {
|
||||
strbuf_trim(&str);
|
||||
if (sq_dequote_to_argv_array(str.buf, array))
|
||||
die("Badly quoted content in file '%s': %s",
|
||||
die(_("Badly quoted content in file '%s': %s"),
|
||||
filename, str.buf);
|
||||
}
|
||||
|
||||
|
@ -646,10 +646,13 @@ static void exit_if_skipped_commits(struct commit_list *tried,
|
|||
|
||||
printf("There are only 'skip'ped commits left to test.\n"
|
||||
"The first %s commit could be any of:\n", term_bad);
|
||||
print_commit_list(tried, "%s\n", "%s\n");
|
||||
|
||||
for ( ; tried; tried = tried->next)
|
||||
printf("%s\n", oid_to_hex(&tried->item->object.oid));
|
||||
|
||||
if (bad)
|
||||
printf("%s\n", oid_to_hex(bad));
|
||||
printf("We cannot bisect more!\n");
|
||||
printf(_("We cannot bisect more!\n"));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
@ -702,7 +705,7 @@ static struct commit *get_commit_reference(const unsigned char *sha1)
|
|||
{
|
||||
struct commit *r = lookup_commit_reference(sha1);
|
||||
if (!r)
|
||||
die("Not a valid commit name %s", sha1_to_hex(sha1));
|
||||
die(_("Not a valid commit name %s"), sha1_to_hex(sha1));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -726,27 +729,27 @@ static void handle_bad_merge_base(void)
|
|||
char *bad_hex = oid_to_hex(current_bad_oid);
|
||||
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
|
||||
if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
|
||||
fprintf(stderr, "The merge base %s is bad.\n"
|
||||
fprintf(stderr, _("The merge base %s is bad.\n"
|
||||
"This means the bug has been fixed "
|
||||
"between %s and [%s].\n",
|
||||
"between %s and [%s].\n"),
|
||||
bad_hex, bad_hex, good_hex);
|
||||
} else if (!strcmp(term_bad, "new") && !strcmp(term_good, "old")) {
|
||||
fprintf(stderr, "The merge base %s is new.\n"
|
||||
fprintf(stderr, _("The merge base %s is new.\n"
|
||||
"The property has changed "
|
||||
"between %s and [%s].\n",
|
||||
"between %s and [%s].\n"),
|
||||
bad_hex, bad_hex, good_hex);
|
||||
} else {
|
||||
fprintf(stderr, "The merge base %s is %s.\n"
|
||||
fprintf(stderr, _("The merge base %s is %s.\n"
|
||||
"This means the first '%s' commit is "
|
||||
"between %s and [%s].\n",
|
||||
"between %s and [%s].\n"),
|
||||
bad_hex, term_bad, term_good, bad_hex, good_hex);
|
||||
}
|
||||
exit(3);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Some %s revs are not ancestor of the %s rev.\n"
|
||||
fprintf(stderr, _("Some %s revs are not ancestor of the %s rev.\n"
|
||||
"git bisect cannot work properly in this case.\n"
|
||||
"Maybe you mistook %s and %s revs?\n",
|
||||
"Maybe you mistook %s and %s revs?\n"),
|
||||
term_good, term_bad, term_good, term_bad);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -754,14 +757,14 @@ static void handle_bad_merge_base(void)
|
|||
static void handle_skipped_merge_base(const unsigned char *mb)
|
||||
{
|
||||
char *mb_hex = sha1_to_hex(mb);
|
||||
char *bad_hex = sha1_to_hex(current_bad_oid->hash);
|
||||
char *bad_hex = oid_to_hex(current_bad_oid);
|
||||
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
|
||||
|
||||
warning("the merge base between %s and [%s] "
|
||||
warning(_("the merge base between %s and [%s] "
|
||||
"must be skipped.\n"
|
||||
"So we cannot be sure the first %s commit is "
|
||||
"between %s and %s.\n"
|
||||
"We continue anyway.",
|
||||
"We continue anyway."),
|
||||
bad_hex, good_hex, term_bad, mb_hex, bad_hex);
|
||||
free(good_hex);
|
||||
}
|
||||
|
@ -792,7 +795,7 @@ static void check_merge_bases(int no_checkout)
|
|||
} else if (0 <= sha1_array_lookup(&skipped_revs, mb)) {
|
||||
handle_skipped_merge_base(mb);
|
||||
} else {
|
||||
printf("Bisecting: a merge base must be tested\n");
|
||||
printf(_("Bisecting: a merge base must be tested\n"));
|
||||
exit(bisect_checkout(mb, no_checkout));
|
||||
}
|
||||
}
|
||||
|
@ -843,7 +846,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
|
|||
int fd;
|
||||
|
||||
if (!current_bad_oid)
|
||||
die("a %s revision is needed", term_bad);
|
||||
die(_("a %s revision is needed"), term_bad);
|
||||
|
||||
/* Check if file BISECT_ANCESTORS_OK exists. */
|
||||
if (!stat(filename, &st) && S_ISREG(st.st_mode))
|
||||
|
@ -860,7 +863,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
|
|||
/* Create file BISECT_ANCESTORS_OK. */
|
||||
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (fd < 0)
|
||||
warning_errno("could not create file '%s'",
|
||||
warning_errno(_("could not create file '%s'"),
|
||||
filename);
|
||||
else
|
||||
close(fd);
|
||||
|
@ -911,7 +914,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
|
|||
*read_good = "good";
|
||||
return;
|
||||
} else {
|
||||
die_errno("could not read file '%s'", filename);
|
||||
die_errno(_("could not read file '%s'"), filename);
|
||||
}
|
||||
} else {
|
||||
strbuf_getline_lf(&str, fp);
|
||||
|
@ -937,10 +940,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
|
|||
struct commit_list *tried;
|
||||
int reaches = 0, all = 0, nr, steps;
|
||||
const unsigned char *bisect_rev;
|
||||
char steps_msg[32];
|
||||
|
||||
read_bisect_terms(&term_bad, &term_good);
|
||||
if (read_bisect_refs())
|
||||
die("reading bisect refs failed");
|
||||
die(_("reading bisect refs failed"));
|
||||
|
||||
check_good_are_ancestors_of_bad(prefix, no_checkout);
|
||||
|
||||
|
@ -960,7 +964,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
|
|||
*/
|
||||
exit_if_skipped_commits(tried, NULL);
|
||||
|
||||
printf("%s was both %s and %s\n",
|
||||
printf(_("%s was both %s and %s\n"),
|
||||
oid_to_hex(current_bad_oid),
|
||||
term_good,
|
||||
term_bad);
|
||||
|
@ -968,8 +972,8 @@ int bisect_next_all(const char *prefix, int no_checkout)
|
|||
}
|
||||
|
||||
if (!all) {
|
||||
fprintf(stderr, "No testable commit found.\n"
|
||||
"Maybe you started with bad path parameters?\n");
|
||||
fprintf(stderr, _("No testable commit found.\n"
|
||||
"Maybe you started with bad path parameters?\n"));
|
||||
exit(4);
|
||||
}
|
||||
|
||||
|
@ -986,9 +990,14 @@ int bisect_next_all(const char *prefix, int no_checkout)
|
|||
|
||||
nr = all - reaches - 1;
|
||||
steps = estimate_bisect_steps(all);
|
||||
printf("Bisecting: %d revision%s left to test after this "
|
||||
"(roughly %d step%s)\n", nr, (nr == 1 ? "" : "s"),
|
||||
steps, (steps == 1 ? "" : "s"));
|
||||
xsnprintf(steps_msg, sizeof(steps_msg),
|
||||
Q_("(roughly %d step)", "(roughly %d steps)", steps),
|
||||
steps);
|
||||
/* TRANSLATORS: the last %s will be replaced with
|
||||
"(roughly %d steps)" translation */
|
||||
printf(Q_("Bisecting: %d revision left to test after this %s\n",
|
||||
"Bisecting: %d revisions left to test after this %s\n",
|
||||
nr), nr, steps_msg);
|
||||
|
||||
return bisect_checkout(bisect_rev, no_checkout);
|
||||
}
|
||||
|
|
105
builtin/am.c
105
builtin/am.c
|
@ -70,7 +70,8 @@ enum patch_format {
|
|||
PATCH_FORMAT_MBOX,
|
||||
PATCH_FORMAT_STGIT,
|
||||
PATCH_FORMAT_STGIT_SERIES,
|
||||
PATCH_FORMAT_HG
|
||||
PATCH_FORMAT_HG,
|
||||
PATCH_FORMAT_MBOXRD
|
||||
};
|
||||
|
||||
enum keep_type {
|
||||
|
@ -183,22 +184,22 @@ static inline const char *am_path(const struct am_state *state, const char *path
|
|||
/**
|
||||
* For convenience to call write_file()
|
||||
*/
|
||||
static int write_state_text(const struct am_state *state,
|
||||
const char *name, const char *string)
|
||||
static void write_state_text(const struct am_state *state,
|
||||
const char *name, const char *string)
|
||||
{
|
||||
return write_file(am_path(state, name), "%s", string);
|
||||
write_file(am_path(state, name), "%s", string);
|
||||
}
|
||||
|
||||
static int write_state_count(const struct am_state *state,
|
||||
static void write_state_count(const struct am_state *state,
|
||||
const char *name, int value)
|
||||
{
|
||||
write_file(am_path(state, name), "%d", value);
|
||||
}
|
||||
|
||||
static void write_state_bool(const struct am_state *state,
|
||||
const char *name, int value)
|
||||
{
|
||||
return write_file(am_path(state, name), "%d", value);
|
||||
}
|
||||
|
||||
static int write_state_bool(const struct am_state *state,
|
||||
const char *name, int value)
|
||||
{
|
||||
return write_state_text(state, name, value ? "t" : "f");
|
||||
write_state_text(state, name, value ? "t" : "f");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -402,13 +403,8 @@ static int read_commit_msg(struct am_state *state)
|
|||
*/
|
||||
static void write_commit_msg(const struct am_state *state)
|
||||
{
|
||||
int fd;
|
||||
const char *filename = am_path(state, "final-commit");
|
||||
|
||||
fd = xopen(filename, O_WRONLY | O_CREAT, 0666);
|
||||
if (write_in_full(fd, state->msg, state->msg_len) < 0)
|
||||
die_errno(_("could not write to %s"), filename);
|
||||
close(fd);
|
||||
write_file_buf(filename, state->msg, state->msg_len);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -712,7 +708,8 @@ done:
|
|||
* Splits out individual email patches from `paths`, where each path is either
|
||||
* a mbox file or a Maildir. Returns 0 on success, -1 on failure.
|
||||
*/
|
||||
static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
|
||||
static int split_mail_mbox(struct am_state *state, const char **paths,
|
||||
int keep_cr, int mboxrd)
|
||||
{
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
struct strbuf last = STRBUF_INIT;
|
||||
|
@ -724,6 +721,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_
|
|||
argv_array_push(&cp.args, "-b");
|
||||
if (keep_cr)
|
||||
argv_array_push(&cp.args, "--keep-cr");
|
||||
if (mboxrd)
|
||||
argv_array_push(&cp.args, "--mboxrd");
|
||||
argv_array_push(&cp.args, "--");
|
||||
argv_array_pushv(&cp.args, paths);
|
||||
|
||||
|
@ -965,13 +964,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
|
|||
|
||||
switch (patch_format) {
|
||||
case PATCH_FORMAT_MBOX:
|
||||
return split_mail_mbox(state, paths, keep_cr);
|
||||
return split_mail_mbox(state, paths, keep_cr, 0);
|
||||
case PATCH_FORMAT_STGIT:
|
||||
return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
|
||||
case PATCH_FORMAT_STGIT_SERIES:
|
||||
return split_mail_stgit_series(state, paths, keep_cr);
|
||||
case PATCH_FORMAT_HG:
|
||||
return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
|
||||
case PATCH_FORMAT_MBOXRD:
|
||||
return split_mail_mbox(state, paths, keep_cr, 1);
|
||||
default:
|
||||
die("BUG: invalid patch_format");
|
||||
}
|
||||
|
@ -1577,48 +1578,19 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the three-way merge using fake ancestor, their tree constructed
|
||||
* from the fake ancestor and the postimage of the patch, and our
|
||||
* state.
|
||||
*/
|
||||
static int run_fallback_merge_recursive(const struct am_state *state,
|
||||
unsigned char *orig_tree,
|
||||
unsigned char *our_tree,
|
||||
unsigned char *their_tree)
|
||||
{
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
int status;
|
||||
|
||||
cp.git_cmd = 1;
|
||||
|
||||
argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s",
|
||||
sha1_to_hex(their_tree), linelen(state->msg), state->msg);
|
||||
if (state->quiet)
|
||||
argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0");
|
||||
|
||||
argv_array_push(&cp.args, "merge-recursive");
|
||||
argv_array_push(&cp.args, sha1_to_hex(orig_tree));
|
||||
argv_array_push(&cp.args, "--");
|
||||
argv_array_push(&cp.args, sha1_to_hex(our_tree));
|
||||
argv_array_push(&cp.args, sha1_to_hex(their_tree));
|
||||
|
||||
status = run_command(&cp) ? (-1) : 0;
|
||||
discard_cache();
|
||||
read_cache();
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt a threeway merge, using index_path as the temporary index.
|
||||
*/
|
||||
static int fall_back_threeway(const struct am_state *state, const char *index_path)
|
||||
{
|
||||
unsigned char orig_tree[GIT_SHA1_RAWSZ], their_tree[GIT_SHA1_RAWSZ],
|
||||
our_tree[GIT_SHA1_RAWSZ];
|
||||
struct object_id orig_tree, their_tree, our_tree;
|
||||
const struct object_id *bases[1] = { &orig_tree };
|
||||
struct merge_options o;
|
||||
struct commit *result;
|
||||
char *their_tree_name;
|
||||
|
||||
if (get_sha1("HEAD", our_tree) < 0)
|
||||
hashcpy(our_tree, EMPTY_TREE_SHA1_BIN);
|
||||
if (get_oid("HEAD", &our_tree) < 0)
|
||||
hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);
|
||||
|
||||
if (build_fake_ancestor(state, index_path))
|
||||
return error("could not build fake ancestor");
|
||||
|
@ -1626,7 +1598,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
|
|||
discard_cache();
|
||||
read_cache_from(index_path);
|
||||
|
||||
if (write_index_as_tree(orig_tree, &the_index, index_path, 0, NULL))
|
||||
if (write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL))
|
||||
return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
|
||||
|
||||
say(state, stdout, _("Using index info to reconstruct a base tree..."));
|
||||
|
@ -1642,7 +1614,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
|
|||
init_revisions(&rev_info, NULL);
|
||||
rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
|
||||
diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
|
||||
add_pending_sha1(&rev_info, "HEAD", our_tree, 0);
|
||||
add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0);
|
||||
diff_setup_done(&rev_info.diffopt);
|
||||
run_diff_index(&rev_info, 1);
|
||||
}
|
||||
|
@ -1651,7 +1623,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
|
|||
return error(_("Did you hand edit your patch?\n"
|
||||
"It does not apply to blobs recorded in its index."));
|
||||
|
||||
if (write_index_as_tree(their_tree, &the_index, index_path, 0, NULL))
|
||||
if (write_index_as_tree(their_tree.hash, &the_index, index_path, 0, NULL))
|
||||
return error("could not write tree");
|
||||
|
||||
say(state, stdout, _("Falling back to patching base and 3-way merge..."));
|
||||
|
@ -1667,11 +1639,22 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
|
|||
* changes.
|
||||
*/
|
||||
|
||||
if (run_fallback_merge_recursive(state, orig_tree, our_tree, their_tree)) {
|
||||
init_merge_options(&o);
|
||||
|
||||
o.branch1 = "HEAD";
|
||||
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
|
||||
o.branch2 = their_tree_name;
|
||||
|
||||
if (state->quiet)
|
||||
o.verbosity = 0;
|
||||
|
||||
if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) {
|
||||
rerere(state->allow_rerere_autoupdate);
|
||||
free(their_tree_name);
|
||||
return error(_("Failed to merge in the changes."));
|
||||
}
|
||||
|
||||
free(their_tree_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2203,6 +2186,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
|
|||
*opt_value = PATCH_FORMAT_STGIT_SERIES;
|
||||
else if (!strcmp(arg, "hg"))
|
||||
*opt_value = PATCH_FORMAT_HG;
|
||||
else if (!strcmp(arg, "mboxrd"))
|
||||
*opt_value = PATCH_FORMAT_MBOXRD;
|
||||
else
|
||||
return error(_("Invalid value for --patch-format: %s"), arg);
|
||||
return 0;
|
||||
|
|
1484
builtin/apply.c
1484
builtin/apply.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -56,7 +56,7 @@ static int show_progress;
|
|||
static struct date_mode blame_date_mode = { DATE_ISO8601 };
|
||||
static size_t blame_date_width;
|
||||
|
||||
static struct string_list mailmap;
|
||||
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
|
@ -598,7 +598,7 @@ static struct origin *find_origin(struct scoreboard *sb,
|
|||
p->status);
|
||||
case 'M':
|
||||
porigin = get_origin(sb, parent, origin->path);
|
||||
hashcpy(porigin->blob_sha1, p->one->sha1);
|
||||
hashcpy(porigin->blob_sha1, p->one->oid.hash);
|
||||
porigin->mode = p->one->mode;
|
||||
break;
|
||||
case 'A':
|
||||
|
@ -608,7 +608,7 @@ static struct origin *find_origin(struct scoreboard *sb,
|
|||
}
|
||||
}
|
||||
diff_flush(&diff_opts);
|
||||
free_pathspec(&diff_opts.pathspec);
|
||||
clear_pathspec(&diff_opts.pathspec);
|
||||
return porigin;
|
||||
}
|
||||
|
||||
|
@ -644,13 +644,13 @@ static struct origin *find_rename(struct scoreboard *sb,
|
|||
if ((p->status == 'R' || p->status == 'C') &&
|
||||
!strcmp(p->two->path, origin->path)) {
|
||||
porigin = get_origin(sb, parent, p->one->path);
|
||||
hashcpy(porigin->blob_sha1, p->one->sha1);
|
||||
hashcpy(porigin->blob_sha1, p->one->oid.hash);
|
||||
porigin->mode = p->one->mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
diff_flush(&diff_opts);
|
||||
free_pathspec(&diff_opts.pathspec);
|
||||
clear_pathspec(&diff_opts.pathspec);
|
||||
return porigin;
|
||||
}
|
||||
|
||||
|
@ -1308,7 +1308,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
|
|||
continue;
|
||||
|
||||
norigin = get_origin(sb, parent, p->one->path);
|
||||
hashcpy(norigin->blob_sha1, p->one->sha1);
|
||||
hashcpy(norigin->blob_sha1, p->one->oid.hash);
|
||||
norigin->mode = p->one->mode;
|
||||
fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
|
||||
if (!file_p.ptr)
|
||||
|
@ -1342,7 +1342,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
|
|||
} while (unblamed);
|
||||
target->suspects = reverse_blame(leftover, NULL);
|
||||
diff_flush(&diff_opts);
|
||||
free_pathspec(&diff_opts.pathspec);
|
||||
clear_pathspec(&diff_opts.pathspec);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2244,7 +2244,8 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
|
|||
pos = cache_name_pos(path, strlen(path));
|
||||
if (pos >= 0)
|
||||
; /* path is in the index */
|
||||
else if (!strcmp(active_cache[-1 - pos]->name, path))
|
||||
else if (-1 - pos < active_nr &&
|
||||
!strcmp(active_cache[-1 - pos]->name, path))
|
||||
; /* path is in the index, unmerged */
|
||||
else
|
||||
die("no such path '%s' in HEAD", path);
|
||||
|
@ -2527,12 +2528,12 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
|||
enum object_type type;
|
||||
struct commit *final_commit = NULL;
|
||||
|
||||
static struct string_list range_list;
|
||||
static int output_option = 0, opt = 0;
|
||||
static int show_stats = 0;
|
||||
static const char *revs_file = NULL;
|
||||
static const char *contents_from = NULL;
|
||||
static const struct option options[] = {
|
||||
struct string_list range_list = STRING_LIST_INIT_NODUP;
|
||||
int output_option = 0, opt = 0;
|
||||
int show_stats = 0;
|
||||
const char *revs_file = NULL;
|
||||
const char *contents_from = NULL;
|
||||
const struct option options[] = {
|
||||
OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
|
||||
OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
|
||||
OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
|
||||
|
@ -2808,7 +2809,7 @@ parse_done:
|
|||
lno = prepare_lines(&sb);
|
||||
|
||||
if (lno && !range_list.nr)
|
||||
string_list_append(&range_list, xstrdup("1"));
|
||||
string_list_append(&range_list, "1");
|
||||
|
||||
anchor = 1;
|
||||
range_set_init(&ranges, range_list.nr);
|
||||
|
|
|
@ -212,7 +212,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||
die(_("Couldn't look up commit object for HEAD"));
|
||||
}
|
||||
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
|
||||
const char *target;
|
||||
char *target = NULL;
|
||||
int flags = 0;
|
||||
|
||||
strbuf_branchname(&bname, argv[i]);
|
||||
|
@ -231,11 +231,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||
}
|
||||
}
|
||||
|
||||
target = resolve_ref_unsafe(name,
|
||||
RESOLVE_REF_READING
|
||||
| RESOLVE_REF_NO_RECURSE
|
||||
| RESOLVE_REF_ALLOW_BAD_NAME,
|
||||
sha1, &flags);
|
||||
target = resolve_refdup(name,
|
||||
RESOLVE_REF_READING
|
||||
| RESOLVE_REF_NO_RECURSE
|
||||
| RESOLVE_REF_ALLOW_BAD_NAME,
|
||||
sha1, &flags);
|
||||
if (!target) {
|
||||
error(remote_branch
|
||||
? _("remote-tracking branch '%s' not found.")
|
||||
|
@ -248,7 +248,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||
check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
|
||||
force)) {
|
||||
ret = 1;
|
||||
continue;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (delete_ref(name, is_null_sha1(sha1) ? NULL : sha1,
|
||||
|
@ -258,7 +258,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||
: _("Error deleting branch '%s'"),
|
||||
bname.buf);
|
||||
ret = 1;
|
||||
continue;
|
||||
goto next;
|
||||
}
|
||||
if (!quiet) {
|
||||
printf(remote_branch
|
||||
|
@ -270,6 +270,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||
: find_unique_abbrev(sha1, DEFAULT_ABBREV));
|
||||
}
|
||||
delete_branch_config(bname.buf);
|
||||
|
||||
next:
|
||||
free(target);
|
||||
}
|
||||
|
||||
free(name);
|
||||
|
@ -614,14 +617,11 @@ static int edit_branch_description(const char *branch_name)
|
|||
if (!buf.len || buf.buf[buf.len-1] != '\n')
|
||||
strbuf_addch(&buf, '\n');
|
||||
strbuf_commented_addf(&buf,
|
||||
"Please edit the description for the branch\n"
|
||||
" %s\n"
|
||||
"Lines starting with '%c' will be stripped.\n",
|
||||
_("Please edit the description for the branch\n"
|
||||
" %s\n"
|
||||
"Lines starting with '%c' will be stripped.\n"),
|
||||
branch_name, comment_line_char);
|
||||
if (write_file_gently(git_path(edit_description), "%s", buf.buf)) {
|
||||
strbuf_release(&buf);
|
||||
return error_errno(_("could not write branch description template"));
|
||||
}
|
||||
write_file_buf(git_path(edit_description), buf.buf, buf.len);
|
||||
strbuf_reset(&buf);
|
||||
if (launch_editor(git_path(edit_description), &buf, NULL)) {
|
||||
strbuf_release(&buf);
|
||||
|
|
|
@ -276,7 +276,7 @@ static int checkout_paths(const struct checkout_opts *opts,
|
|||
|
||||
hold_locked_index(lock_file, 1);
|
||||
if (read_cache_preload(&opts->pathspec) < 0)
|
||||
return error(_("corrupt index file"));
|
||||
return error(_("index file corrupt"));
|
||||
|
||||
if (opts->source_tree)
|
||||
read_tree_some(opts->source_tree, &opts->pathspec);
|
||||
|
@ -470,7 +470,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
|
|||
|
||||
hold_locked_index(lock_file, 1);
|
||||
if (read_cache_preload(NULL) < 0)
|
||||
return error(_("corrupt index file"));
|
||||
return error(_("index file corrupt"));
|
||||
|
||||
resolve_undo_clear();
|
||||
if (opts->force) {
|
||||
|
@ -567,10 +567,13 @@ static int merge_working_tree(const struct checkout_opts *opts,
|
|||
o.ancestor = old->name;
|
||||
o.branch1 = new->name;
|
||||
o.branch2 = "local";
|
||||
merge_trees(&o, new->commit->tree, work,
|
||||
ret = merge_trees(&o, new->commit->tree, work,
|
||||
old->commit->tree, &result);
|
||||
if (ret < 0)
|
||||
exit(128);
|
||||
ret = reset_tree(new->commit->tree, opts, 0,
|
||||
writeout_error);
|
||||
strbuf_release(&o.obuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -1138,7 +1141,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
|||
OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
|
||||
N_("create/reset and checkout a branch")),
|
||||
OPT_BOOL('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
|
||||
OPT_BOOL(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
|
||||
OPT_BOOL(0, "detach", &opts.force_detach, N_("detach HEAD at named commit")),
|
||||
OPT_SET_INT('t', "track", &opts.track, N_("set upstream info for new branch"),
|
||||
BRANCH_TRACK_EXPLICIT),
|
||||
OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
|
||||
|
|
|
@ -49,8 +49,8 @@ static char *option_upload_pack = "git-upload-pack";
|
|||
static int option_verbosity;
|
||||
static int option_progress = -1;
|
||||
static enum transport_family family;
|
||||
static struct string_list option_config;
|
||||
static struct string_list option_reference;
|
||||
static struct string_list option_config = STRING_LIST_INIT_NODUP;
|
||||
static struct string_list option_reference = STRING_LIST_INIT_NODUP;
|
||||
static int option_dissociate;
|
||||
static int max_jobs = -1;
|
||||
|
||||
|
@ -624,13 +624,13 @@ static void update_remote_refs(const struct ref *refs,
|
|||
const struct ref *rm = mapped_refs;
|
||||
|
||||
if (check_connectivity) {
|
||||
if (transport->progress)
|
||||
fprintf(stderr, _("Checking connectivity... "));
|
||||
if (check_everything_connected_with_transport(iterate_ref_map,
|
||||
0, &rm, transport))
|
||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||
|
||||
opt.transport = transport;
|
||||
opt.progress = transport->progress;
|
||||
|
||||
if (check_connected(iterate_ref_map, &rm, &opt))
|
||||
die(_("remote did not send all necessary objects"));
|
||||
if (transport->progress)
|
||||
fprintf(stderr, _("done.\n"));
|
||||
}
|
||||
|
||||
if (refs) {
|
||||
|
|
|
@ -25,7 +25,6 @@ static char term = '\n';
|
|||
static int use_global_config, use_system_config, use_local_config;
|
||||
static struct git_config_source given_config_source;
|
||||
static int actions, types;
|
||||
static const char *get_color_slot, *get_colorbool_slot;
|
||||
static int end_null;
|
||||
static int respect_includes = -1;
|
||||
static int show_origin;
|
||||
|
@ -604,7 +603,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
|||
given_config_source.file : git_path("config"));
|
||||
if (use_global_config) {
|
||||
int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
|
||||
if (fd) {
|
||||
if (fd >= 0) {
|
||||
char *content = default_user_config();
|
||||
write_str_in_full(fd, content);
|
||||
free(content);
|
||||
|
|
|
@ -368,7 +368,7 @@ static void show_filemodify(struct diff_queue_struct *q,
|
|||
print_path(spec->path);
|
||||
putchar('\n');
|
||||
|
||||
if (!hashcmp(ospec->sha1, spec->sha1) &&
|
||||
if (!oidcmp(&ospec->oid, &spec->oid) &&
|
||||
ospec->mode == spec->mode)
|
||||
break;
|
||||
/* fallthrough */
|
||||
|
@ -383,10 +383,10 @@ static void show_filemodify(struct diff_queue_struct *q,
|
|||
if (no_data || S_ISGITLINK(spec->mode))
|
||||
printf("M %06o %s ", spec->mode,
|
||||
sha1_to_hex(anonymize ?
|
||||
anonymize_sha1(spec->sha1) :
|
||||
spec->sha1));
|
||||
anonymize_sha1(spec->oid.hash) :
|
||||
spec->oid.hash));
|
||||
else {
|
||||
struct object *object = lookup_object(spec->sha1);
|
||||
struct object *object = lookup_object(spec->oid.hash);
|
||||
printf("M %06o :%d ", spec->mode,
|
||||
get_object_mark(object));
|
||||
}
|
||||
|
@ -572,7 +572,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
|
|||
/* Export the referenced blobs, and remember the marks. */
|
||||
for (i = 0; i < diff_queued_diff.nr; i++)
|
||||
if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
|
||||
export_blob(diff_queued_diff.queue[i]->two->sha1);
|
||||
export_blob(diff_queued_diff.queue[i]->two->oid.hash);
|
||||
|
||||
refname = commit->util;
|
||||
if (anonymize) {
|
||||
|
|
205
builtin/fetch.c
205
builtin/fetch.c
|
@ -15,6 +15,7 @@
|
|||
#include "submodule.h"
|
||||
#include "connected.h"
|
||||
#include "argv-array.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static const char * const builtin_fetch_usage[] = {
|
||||
N_("git fetch [<options>] [<repository> [<refspec>...]]"),
|
||||
|
@ -449,7 +450,132 @@ fail:
|
|||
: STORE_REF_ERROR_OTHER;
|
||||
}
|
||||
|
||||
#define REFCOL_WIDTH 10
|
||||
static int refcol_width = 10;
|
||||
static int compact_format;
|
||||
|
||||
static void adjust_refcol_width(const struct ref *ref)
|
||||
{
|
||||
int max, rlen, llen, len;
|
||||
|
||||
/* uptodate lines are only shown on high verbosity level */
|
||||
if (!verbosity && !oidcmp(&ref->peer_ref->old_oid, &ref->old_oid))
|
||||
return;
|
||||
|
||||
max = term_columns();
|
||||
rlen = utf8_strwidth(prettify_refname(ref->name));
|
||||
|
||||
llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
|
||||
|
||||
/*
|
||||
* rough estimation to see if the output line is too long and
|
||||
* should not be counted (we can't do precise calculation
|
||||
* anyway because we don't know if the error explanation part
|
||||
* will be printed in update_local_ref)
|
||||
*/
|
||||
if (compact_format) {
|
||||
llen = 0;
|
||||
max = max * 2 / 3;
|
||||
}
|
||||
len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
|
||||
if (len >= max)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Not precise calculation for compact mode because '*' can
|
||||
* appear on the left hand side of '->' and shrink the column
|
||||
* back.
|
||||
*/
|
||||
if (refcol_width < rlen)
|
||||
refcol_width = rlen;
|
||||
}
|
||||
|
||||
static void prepare_format_display(struct ref *ref_map)
|
||||
{
|
||||
struct ref *rm;
|
||||
const char *format = "full";
|
||||
|
||||
git_config_get_string_const("fetch.output", &format);
|
||||
if (!strcasecmp(format, "full"))
|
||||
compact_format = 0;
|
||||
else if (!strcasecmp(format, "compact"))
|
||||
compact_format = 1;
|
||||
else
|
||||
die(_("configuration fetch.output contains invalid value %s"),
|
||||
format);
|
||||
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
if (rm->status == REF_STATUS_REJECT_SHALLOW ||
|
||||
!rm->peer_ref ||
|
||||
!strcmp(rm->name, "HEAD"))
|
||||
continue;
|
||||
|
||||
adjust_refcol_width(rm);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_remote_to_local(struct strbuf *display,
|
||||
const char *remote, const char *local)
|
||||
{
|
||||
strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
|
||||
}
|
||||
|
||||
static int find_and_replace(struct strbuf *haystack,
|
||||
const char *needle,
|
||||
const char *placeholder)
|
||||
{
|
||||
const char *p = strstr(haystack->buf, needle);
|
||||
int plen, nlen;
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
if (p > haystack->buf && p[-1] != '/')
|
||||
return 0;
|
||||
|
||||
plen = strlen(p);
|
||||
nlen = strlen(needle);
|
||||
if (plen > nlen && p[nlen] != '/')
|
||||
return 0;
|
||||
|
||||
strbuf_splice(haystack, p - haystack->buf, nlen,
|
||||
placeholder, strlen(placeholder));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void print_compact(struct strbuf *display,
|
||||
const char *remote, const char *local)
|
||||
{
|
||||
struct strbuf r = STRBUF_INIT;
|
||||
struct strbuf l = STRBUF_INIT;
|
||||
|
||||
if (!strcmp(remote, local)) {
|
||||
strbuf_addf(display, "%-*s -> *", refcol_width, remote);
|
||||
return;
|
||||
}
|
||||
|
||||
strbuf_addstr(&r, remote);
|
||||
strbuf_addstr(&l, local);
|
||||
|
||||
if (!find_and_replace(&r, local, "*"))
|
||||
find_and_replace(&l, remote, "*");
|
||||
print_remote_to_local(display, r.buf, l.buf);
|
||||
|
||||
strbuf_release(&r);
|
||||
strbuf_release(&l);
|
||||
}
|
||||
|
||||
static void format_display(struct strbuf *display, char code,
|
||||
const char *summary, const char *error,
|
||||
const char *remote, const char *local)
|
||||
{
|
||||
strbuf_addf(display, "%c %-*s ", code, TRANSPORT_SUMMARY(summary));
|
||||
if (!compact_format)
|
||||
print_remote_to_local(display, remote, local);
|
||||
else
|
||||
print_compact(display, remote, local);
|
||||
if (error)
|
||||
strbuf_addf(display, " (%s)", error);
|
||||
}
|
||||
|
||||
static int update_local_ref(struct ref *ref,
|
||||
const char *remote,
|
||||
|
@ -467,9 +593,8 @@ static int update_local_ref(struct ref *ref,
|
|||
|
||||
if (!oidcmp(&ref->old_oid, &ref->new_oid)) {
|
||||
if (verbosity > 0)
|
||||
strbuf_addf(display, "= %-*s %-*s -> %s",
|
||||
TRANSPORT_SUMMARY(_("[up to date]")),
|
||||
REFCOL_WIDTH, remote, pretty_ref);
|
||||
format_display(display, '=', _("[up to date]"), NULL,
|
||||
remote, pretty_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -481,10 +606,9 @@ static int update_local_ref(struct ref *ref,
|
|||
* If this is the head, and it's not okay to update
|
||||
* the head, and the old value of the head isn't empty...
|
||||
*/
|
||||
strbuf_addf(display,
|
||||
_("! %-*s %-*s -> %s (can't fetch in current branch)"),
|
||||
TRANSPORT_SUMMARY(_("[rejected]")),
|
||||
REFCOL_WIDTH, remote, pretty_ref);
|
||||
format_display(display, '!', _("[rejected]"),
|
||||
_("can't fetch in current branch"),
|
||||
remote, pretty_ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -492,11 +616,9 @@ static int update_local_ref(struct ref *ref,
|
|||
starts_with(ref->name, "refs/tags/")) {
|
||||
int r;
|
||||
r = s_update_ref("updating tag", ref, 0);
|
||||
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
|
||||
r ? '!' : '-',
|
||||
TRANSPORT_SUMMARY(_("[tag update]")),
|
||||
REFCOL_WIDTH, remote, pretty_ref,
|
||||
r ? _(" (unable to update local ref)") : "");
|
||||
format_display(display, r ? '!' : 't', _("[tag update]"),
|
||||
r ? _("unable to update local ref") : NULL,
|
||||
remote, pretty_ref);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -527,11 +649,9 @@ static int update_local_ref(struct ref *ref,
|
|||
(recurse_submodules != RECURSE_SUBMODULES_ON))
|
||||
check_for_new_submodule_commits(ref->new_oid.hash);
|
||||
r = s_update_ref(msg, ref, 0);
|
||||
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
|
||||
r ? '!' : '*',
|
||||
TRANSPORT_SUMMARY(what),
|
||||
REFCOL_WIDTH, remote, pretty_ref,
|
||||
r ? _(" (unable to update local ref)") : "");
|
||||
format_display(display, r ? '!' : '*', what,
|
||||
r ? _("unable to update local ref") : NULL,
|
||||
remote, pretty_ref);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -545,11 +665,9 @@ static int update_local_ref(struct ref *ref,
|
|||
(recurse_submodules != RECURSE_SUBMODULES_ON))
|
||||
check_for_new_submodule_commits(ref->new_oid.hash);
|
||||
r = s_update_ref("fast-forward", ref, 1);
|
||||
strbuf_addf(display, "%c %-*s %-*s -> %s%s",
|
||||
r ? '!' : ' ',
|
||||
TRANSPORT_SUMMARY_WIDTH, quickref.buf,
|
||||
REFCOL_WIDTH, remote, pretty_ref,
|
||||
r ? _(" (unable to update local ref)") : "");
|
||||
format_display(display, r ? '!' : ' ', quickref.buf,
|
||||
r ? _("unable to update local ref") : NULL,
|
||||
remote, pretty_ref);
|
||||
strbuf_release(&quickref);
|
||||
return r;
|
||||
} else if (force || ref->force) {
|
||||
|
@ -562,18 +680,14 @@ static int update_local_ref(struct ref *ref,
|
|||
(recurse_submodules != RECURSE_SUBMODULES_ON))
|
||||
check_for_new_submodule_commits(ref->new_oid.hash);
|
||||
r = s_update_ref("forced-update", ref, 1);
|
||||
strbuf_addf(display, "%c %-*s %-*s -> %s (%s)",
|
||||
r ? '!' : '+',
|
||||
TRANSPORT_SUMMARY_WIDTH, quickref.buf,
|
||||
REFCOL_WIDTH, remote, pretty_ref,
|
||||
r ? _("unable to update local ref") : _("forced update"));
|
||||
format_display(display, r ? '!' : '+', quickref.buf,
|
||||
r ? _("unable to update local ref") : _("forced update"),
|
||||
remote, pretty_ref);
|
||||
strbuf_release(&quickref);
|
||||
return r;
|
||||
} else {
|
||||
strbuf_addf(display, "! %-*s %-*s -> %s %s",
|
||||
TRANSPORT_SUMMARY(_("[rejected]")),
|
||||
REFCOL_WIDTH, remote, pretty_ref,
|
||||
_("(non-fast-forward)"));
|
||||
format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
|
||||
remote, pretty_ref);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -615,11 +729,13 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
|||
url = xstrdup("foreign");
|
||||
|
||||
rm = ref_map;
|
||||
if (check_everything_connected(iterate_ref_map, 0, &rm)) {
|
||||
if (check_connected(iterate_ref_map, &rm, NULL)) {
|
||||
rc = error(_("%s did not send all necessary objects\n"), url);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
prepare_format_display(ref_map);
|
||||
|
||||
/*
|
||||
* We do a pass for each fetch_head_status type in their enum order, so
|
||||
* merged entries are written before not-for-merge. That lets readers
|
||||
|
@ -714,11 +830,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
|||
rc |= update_local_ref(ref, what, rm, ¬e);
|
||||
free(ref);
|
||||
} else
|
||||
strbuf_addf(¬e, "* %-*s %-*s -> FETCH_HEAD",
|
||||
TRANSPORT_SUMMARY_WIDTH,
|
||||
*kind ? kind : "branch",
|
||||
REFCOL_WIDTH,
|
||||
*what ? what : "HEAD");
|
||||
format_display(¬e, '*',
|
||||
*kind ? kind : "branch", NULL,
|
||||
*what ? what : "HEAD",
|
||||
"FETCH_HEAD");
|
||||
if (note.len) {
|
||||
if (verbosity >= 0 && !shown_url) {
|
||||
fprintf(stderr, _("From %.*s\n"),
|
||||
|
@ -751,6 +866,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
|||
static int quickfetch(struct ref *ref_map)
|
||||
{
|
||||
struct ref *rm = ref_map;
|
||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||
|
||||
/*
|
||||
* If we are deepening a shallow clone we already have these
|
||||
|
@ -761,7 +877,8 @@ static int quickfetch(struct ref *ref_map)
|
|||
*/
|
||||
if (depth)
|
||||
return -1;
|
||||
return check_everything_connected(iterate_ref_map, 1, &rm);
|
||||
opt.quiet = 1;
|
||||
return check_connected(iterate_ref_map, &rm, &opt);
|
||||
}
|
||||
|
||||
static int fetch_refs(struct transport *transport, struct ref *ref_map)
|
||||
|
@ -806,19 +923,21 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
|
|||
for (ref = stale_refs; ref; ref = ref->next)
|
||||
string_list_append(&refnames, ref->name);
|
||||
|
||||
result = delete_refs(&refnames);
|
||||
result = delete_refs(&refnames, 0);
|
||||
string_list_clear(&refnames, 0);
|
||||
}
|
||||
|
||||
if (verbosity >= 0) {
|
||||
for (ref = stale_refs; ref; ref = ref->next) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
if (!shown_url) {
|
||||
fprintf(stderr, _("From %.*s\n"), url_len, url);
|
||||
shown_url = 1;
|
||||
}
|
||||
fprintf(stderr, " x %-*s %-*s -> %s\n",
|
||||
TRANSPORT_SUMMARY(_("[deleted]")),
|
||||
REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
|
||||
format_display(&sb, '-', _("[deleted]"), NULL,
|
||||
_("(none)"), prettify_refname(ref->name));
|
||||
fprintf(stderr, " %s\n",sb.buf);
|
||||
strbuf_release(&sb);
|
||||
warn_dangling_symref(stderr, dangling_msg, ref->name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "dir.h"
|
||||
#include "progress.h"
|
||||
#include "streaming.h"
|
||||
#include "decorate.h"
|
||||
|
||||
#define REACHABLE 0x0001
|
||||
#define SEEN 0x0002
|
||||
|
@ -35,11 +36,26 @@ static int write_lost_and_found;
|
|||
static int verbose;
|
||||
static int show_progress = -1;
|
||||
static int show_dangling = 1;
|
||||
static int name_objects;
|
||||
#define ERROR_OBJECT 01
|
||||
#define ERROR_REACHABLE 02
|
||||
#define ERROR_PACK 04
|
||||
#define ERROR_REFS 010
|
||||
|
||||
static const char *describe_object(struct object *obj)
|
||||
{
|
||||
static struct strbuf buf = STRBUF_INIT;
|
||||
char *name = name_objects ?
|
||||
lookup_decoration(fsck_walk_options.object_names, obj) : NULL;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, oid_to_hex(&obj->oid));
|
||||
if (name)
|
||||
strbuf_addf(&buf, " (%s)", name);
|
||||
|
||||
return buf.buf;
|
||||
}
|
||||
|
||||
static int fsck_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (strcmp(var, "fsck.skiplist") == 0) {
|
||||
|
@ -67,7 +83,7 @@ static void objreport(struct object *obj, const char *msg_type,
|
|||
const char *err)
|
||||
{
|
||||
fprintf(stderr, "%s in %s %s: %s\n",
|
||||
msg_type, typename(obj->type), oid_to_hex(&obj->oid), err);
|
||||
msg_type, typename(obj->type), describe_object(obj), err);
|
||||
}
|
||||
|
||||
static int objerror(struct object *obj, const char *err)
|
||||
|
@ -77,7 +93,8 @@ static int objerror(struct object *obj, const char *err)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int fsck_error_func(struct object *obj, int type, const char *message)
|
||||
static int fsck_error_func(struct fsck_options *o,
|
||||
struct object *obj, int type, const char *message)
|
||||
{
|
||||
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", message);
|
||||
return (type == FSCK_WARN) ? 0 : 1;
|
||||
|
@ -97,7 +114,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
|
|||
if (!obj) {
|
||||
/* ... these references to parent->fld are safe here */
|
||||
printf("broken link from %7s %s\n",
|
||||
typename(parent->type), oid_to_hex(&parent->oid));
|
||||
typename(parent->type), describe_object(parent));
|
||||
printf("broken link from %7s %s\n",
|
||||
(type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
|
@ -114,9 +131,9 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
|
|||
if (!(obj->flags & HAS_OBJ)) {
|
||||
if (parent && !has_object_file(&obj->oid)) {
|
||||
printf("broken link from %7s %s\n",
|
||||
typename(parent->type), oid_to_hex(&parent->oid));
|
||||
typename(parent->type), describe_object(parent));
|
||||
printf(" to %7s %s\n",
|
||||
typename(obj->type), oid_to_hex(&obj->oid));
|
||||
typename(obj->type), describe_object(obj));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
}
|
||||
return 1;
|
||||
|
@ -190,7 +207,8 @@ static void check_reachable_object(struct object *obj)
|
|||
return; /* it is in pack - forget about it */
|
||||
if (connectivity_only && has_object_file(&obj->oid))
|
||||
return;
|
||||
printf("missing %s %s\n", typename(obj->type), oid_to_hex(&obj->oid));
|
||||
printf("missing %s %s\n", typename(obj->type),
|
||||
describe_object(obj));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
return;
|
||||
}
|
||||
|
@ -215,7 +233,8 @@ static void check_unreachable_object(struct object *obj)
|
|||
* since this is something that is prunable.
|
||||
*/
|
||||
if (show_unreachable) {
|
||||
printf("unreachable %s %s\n", typename(obj->type), oid_to_hex(&obj->oid));
|
||||
printf("unreachable %s %s\n", typename(obj->type),
|
||||
describe_object(obj));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -234,11 +253,11 @@ static void check_unreachable_object(struct object *obj)
|
|||
if (!obj->used) {
|
||||
if (show_dangling)
|
||||
printf("dangling %s %s\n", typename(obj->type),
|
||||
oid_to_hex(&obj->oid));
|
||||
describe_object(obj));
|
||||
if (write_lost_and_found) {
|
||||
char *filename = git_pathdup("lost-found/%s/%s",
|
||||
obj->type == OBJ_COMMIT ? "commit" : "other",
|
||||
oid_to_hex(&obj->oid));
|
||||
describe_object(obj));
|
||||
FILE *f;
|
||||
|
||||
if (safe_create_leading_directories_const(filename)) {
|
||||
|
@ -252,7 +271,7 @@ static void check_unreachable_object(struct object *obj)
|
|||
if (stream_blob_to_fd(fileno(f), obj->oid.hash, NULL, 1))
|
||||
die_errno("Could not write '%s'", filename);
|
||||
} else
|
||||
fprintf(f, "%s\n", oid_to_hex(&obj->oid));
|
||||
fprintf(f, "%s\n", describe_object(obj));
|
||||
if (fclose(f))
|
||||
die_errno("Could not finish '%s'",
|
||||
filename);
|
||||
|
@ -271,7 +290,7 @@ static void check_unreachable_object(struct object *obj)
|
|||
static void check_object(struct object *obj)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf(stderr, "Checking %s\n", oid_to_hex(&obj->oid));
|
||||
fprintf(stderr, "Checking %s\n", describe_object(obj));
|
||||
|
||||
if (obj->flags & REACHABLE)
|
||||
check_reachable_object(obj);
|
||||
|
@ -307,7 +326,7 @@ static int fsck_obj(struct object *obj)
|
|||
|
||||
if (verbose)
|
||||
fprintf(stderr, "Checking %s %s\n",
|
||||
typename(obj->type), oid_to_hex(&obj->oid));
|
||||
typename(obj->type), describe_object(obj));
|
||||
|
||||
if (fsck_walk(obj, NULL, &fsck_obj_options))
|
||||
objerror(obj, "broken links");
|
||||
|
@ -326,15 +345,17 @@ static int fsck_obj(struct object *obj)
|
|||
free_commit_buffer(commit);
|
||||
|
||||
if (!commit->parents && show_root)
|
||||
printf("root %s\n", oid_to_hex(&commit->object.oid));
|
||||
printf("root %s\n", describe_object(&commit->object));
|
||||
}
|
||||
|
||||
if (obj->type == OBJ_TAG) {
|
||||
struct tag *tag = (struct tag *) obj;
|
||||
|
||||
if (show_tags && tag->tagged) {
|
||||
printf("tagged %s %s", typename(tag->tagged->type), oid_to_hex(&tag->tagged->oid));
|
||||
printf(" (%s) in %s\n", tag->tag, oid_to_hex(&tag->object.oid));
|
||||
printf("tagged %s %s", typename(tag->tagged->type),
|
||||
describe_object(tag->tagged));
|
||||
printf(" (%s) in %s\n", tag->tag,
|
||||
describe_object(&tag->object));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,13 +393,18 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
|
|||
|
||||
static int default_refs;
|
||||
|
||||
static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1)
|
||||
static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
if (!is_null_sha1(sha1)) {
|
||||
obj = lookup_object(sha1);
|
||||
if (obj) {
|
||||
if (timestamp && name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj,
|
||||
xstrfmt("%s@{%ld}", refname, timestamp));
|
||||
obj->used = 1;
|
||||
mark_object_reachable(obj);
|
||||
} else {
|
||||
|
@ -398,8 +424,8 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
|
|||
fprintf(stderr, "Checking reflog %s->%s\n",
|
||||
sha1_to_hex(osha1), sha1_to_hex(nsha1));
|
||||
|
||||
fsck_handle_reflog_sha1(refname, osha1);
|
||||
fsck_handle_reflog_sha1(refname, nsha1);
|
||||
fsck_handle_reflog_sha1(refname, osha1, 0);
|
||||
fsck_handle_reflog_sha1(refname, nsha1, timestamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -428,6 +454,9 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
|
|||
}
|
||||
default_refs++;
|
||||
obj->used = 1;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj, xstrdup(refname));
|
||||
mark_object_reachable(obj);
|
||||
|
||||
return 0;
|
||||
|
@ -543,6 +572,9 @@ static int fsck_cache_tree(struct cache_tree *it)
|
|||
return 1;
|
||||
}
|
||||
obj->used = 1;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj, xstrdup(":"));
|
||||
mark_object_reachable(obj);
|
||||
if (obj->type != OBJ_TREE)
|
||||
err |= objerror(obj, "non-tree in cache-tree");
|
||||
|
@ -571,6 +603,7 @@ static struct option fsck_opts[] = {
|
|||
OPT_BOOL(0, "lost-found", &write_lost_and_found,
|
||||
N_("write dangling objects in .git/lost-found")),
|
||||
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
|
||||
OPT_BOOL(0, "name-objects", &name_objects, N_("show verbose names for reachable objects")),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
|
@ -600,6 +633,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
|||
include_reflogs = 0;
|
||||
}
|
||||
|
||||
if (name_objects)
|
||||
fsck_walk_options.object_names =
|
||||
xcalloc(1, sizeof(struct decoration));
|
||||
|
||||
git_config(fsck_config, NULL);
|
||||
|
||||
fsck_head_link();
|
||||
|
@ -655,6 +692,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
|||
continue;
|
||||
|
||||
obj->used = 1;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj, xstrdup(arg));
|
||||
mark_object_reachable(obj);
|
||||
heads++;
|
||||
continue;
|
||||
|
@ -687,6 +727,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
|||
continue;
|
||||
obj = &blob->object;
|
||||
obj->used = 1;
|
||||
if (name_objects)
|
||||
add_decoration(fsck_walk_options.object_names,
|
||||
obj,
|
||||
xstrfmt(":%s", active_cache[i]->name));
|
||||
mark_object_reachable(obj);
|
||||
}
|
||||
if (active_cache_tree)
|
||||
|
|
|
@ -77,6 +77,7 @@ static int strict;
|
|||
static int do_fsck_object;
|
||||
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
|
||||
static int verbose;
|
||||
static int show_resolving_progress;
|
||||
static int show_stat;
|
||||
static int check_self_contained_and_connected;
|
||||
|
||||
|
@ -1191,7 +1192,7 @@ static void resolve_deltas(void)
|
|||
qsort(ref_deltas, nr_ref_deltas, sizeof(struct ref_delta_entry),
|
||||
compare_ref_delta_entry);
|
||||
|
||||
if (verbose)
|
||||
if (verbose || show_resolving_progress)
|
||||
progress = start_progress(_("Resolving deltas"),
|
||||
nr_ref_deltas + nr_ofs_deltas);
|
||||
|
||||
|
@ -1626,6 +1627,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
|||
struct pack_idx_option opts;
|
||||
unsigned char pack_sha1[20];
|
||||
unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
|
||||
int report_end_of_input = 0;
|
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "-h"))
|
||||
usage(index_pack_usage);
|
||||
|
@ -1695,6 +1697,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
|||
input_len = sizeof(*hdr);
|
||||
} else if (!strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
} else if (!strcmp(arg, "--show-resolving-progress")) {
|
||||
show_resolving_progress = 1;
|
||||
} else if (!strcmp(arg, "--report-end-of-input")) {
|
||||
report_end_of_input = 1;
|
||||
} else if (!strcmp(arg, "-o")) {
|
||||
if (index_name || (i+1) >= argc)
|
||||
usage(index_pack_usage);
|
||||
|
@ -1752,6 +1758,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
|||
obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
|
||||
ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
|
||||
parse_pack_objects(pack_sha1);
|
||||
if (report_end_of_input)
|
||||
write_in_full(2, "\0", 1);
|
||||
resolve_deltas();
|
||||
conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
|
||||
free(ofs_deltas);
|
||||
|
|
|
@ -397,13 +397,16 @@ int init_db(const char *template_dir, unsigned int flags)
|
|||
if (!(flags & INIT_DB_QUIET)) {
|
||||
int len = strlen(git_dir);
|
||||
|
||||
/* TRANSLATORS: The first '%s' is either "Reinitialized
|
||||
existing" or "Initialized empty", the second " shared" or
|
||||
"", and the last '%s%s' is the verbatim directory name. */
|
||||
printf(_("%s%s Git repository in %s%s\n"),
|
||||
reinit ? _("Reinitialized existing") : _("Initialized empty"),
|
||||
get_shared_repository() ? _(" shared") : "",
|
||||
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
|
||||
if (reinit)
|
||||
printf(get_shared_repository()
|
||||
? _("Reinitialized existing shared Git repository in %s%s\n")
|
||||
: _("Reinitialized existing Git repository in %s%s\n"),
|
||||
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
|
||||
else
|
||||
printf(get_shared_repository()
|
||||
? _("Initialized empty shared Git repository in %s%s\n")
|
||||
: _("Initialized empty Git repository in %s%s\n"),
|
||||
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -20,7 +20,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
|
|||
{
|
||||
int in_place = 0;
|
||||
int trim_empty = 0;
|
||||
struct string_list trailers = STRING_LIST_INIT_DUP;
|
||||
struct string_list trailers = STRING_LIST_INIT_NODUP;
|
||||
|
||||
struct option options[] = {
|
||||
OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
|
||||
|
|
116
builtin/log.c
116
builtin/log.c
|
@ -33,6 +33,7 @@ static const char *default_date_mode = NULL;
|
|||
static int default_abbrev_commit;
|
||||
static int default_show_root = 1;
|
||||
static int default_follow;
|
||||
static int default_show_signature;
|
||||
static int decoration_style;
|
||||
static int decoration_given;
|
||||
static int use_mailmap_config;
|
||||
|
@ -119,6 +120,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
|
|||
rev->abbrev_commit = default_abbrev_commit;
|
||||
rev->show_root_diff = default_show_root;
|
||||
rev->subject_prefix = fmt_patch_subject_prefix;
|
||||
rev->show_signature = default_show_signature;
|
||||
DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
|
||||
|
||||
if (default_date_mode)
|
||||
|
@ -236,16 +238,17 @@ static void show_early_header(struct rev_info *rev, const char *stage, int nr)
|
|||
if (rev->commit_format != CMIT_FMT_ONELINE)
|
||||
putchar(rev->diffopt.line_termination);
|
||||
}
|
||||
printf(_("Final output: %d %s\n"), nr, stage);
|
||||
fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage);
|
||||
}
|
||||
|
||||
static struct itimerval early_output_timer;
|
||||
|
||||
static void log_show_early(struct rev_info *revs, struct commit_list *list)
|
||||
{
|
||||
int i = revs->early_output;
|
||||
int i = revs->early_output, close_file = revs->diffopt.close_file;
|
||||
int show_header = 1;
|
||||
|
||||
revs->diffopt.close_file = 0;
|
||||
sort_in_topological_order(&list, revs->sort_order);
|
||||
while (list && i) {
|
||||
struct commit *commit = list->item;
|
||||
|
@ -262,14 +265,19 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
|
|||
case commit_ignore:
|
||||
break;
|
||||
case commit_error:
|
||||
if (close_file)
|
||||
fclose(revs->diffopt.file);
|
||||
return;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Did we already get enough commits for the early output? */
|
||||
if (!i)
|
||||
if (!i) {
|
||||
if (close_file)
|
||||
fclose(revs->diffopt.file);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* ..if no, then repeat it twice a second until we
|
||||
|
@ -331,7 +339,7 @@ static int cmd_log_walk(struct rev_info *rev)
|
|||
{
|
||||
struct commit *commit;
|
||||
int saved_nrl = 0;
|
||||
int saved_dcctc = 0;
|
||||
int saved_dcctc = 0, close_file = rev->diffopt.close_file;
|
||||
|
||||
if (rev->early_output)
|
||||
setup_early_output(rev);
|
||||
|
@ -347,6 +355,7 @@ static int cmd_log_walk(struct rev_info *rev)
|
|||
* and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
|
||||
* retain that state information if replacing rev->diffopt in this loop
|
||||
*/
|
||||
rev->diffopt.close_file = 0;
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
|
||||
/*
|
||||
|
@ -367,6 +376,8 @@ static int cmd_log_walk(struct rev_info *rev)
|
|||
}
|
||||
rev->diffopt.degraded_cc_to_c = saved_dcctc;
|
||||
rev->diffopt.needed_rename_limit = saved_nrl;
|
||||
if (close_file)
|
||||
fclose(rev->diffopt.file);
|
||||
|
||||
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
|
||||
DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
|
||||
|
@ -409,6 +420,10 @@ static int git_log_config(const char *var, const char *value, void *cb)
|
|||
use_mailmap_config = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "log.showsignature")) {
|
||||
default_show_signature = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grep_config(var, value, cb) < 0)
|
||||
return -1;
|
||||
|
@ -445,7 +460,7 @@ static void show_tagger(char *buf, int len, struct rev_info *rev)
|
|||
pp.fmt = rev->commit_format;
|
||||
pp.date_mode = rev->date_mode;
|
||||
pp_user_info(&pp, "Tagger", &out, buf, get_log_output_encoding());
|
||||
printf("%s", out.buf);
|
||||
fprintf(rev->diffopt.file, "%s", out.buf);
|
||||
strbuf_release(&out);
|
||||
}
|
||||
|
||||
|
@ -456,7 +471,7 @@ static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, con
|
|||
char *buf;
|
||||
unsigned long size;
|
||||
|
||||
fflush(stdout);
|
||||
fflush(rev->diffopt.file);
|
||||
if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
|
||||
!DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
|
||||
return stream_blob_to_fd(1, sha1, NULL, 0);
|
||||
|
@ -496,7 +511,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
|
|||
}
|
||||
|
||||
if (offset < size)
|
||||
fwrite(buf + offset, size - offset, 1, stdout);
|
||||
fwrite(buf + offset, size - offset, 1, rev->diffopt.file);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
@ -505,7 +520,8 @@ static int show_tree_object(const unsigned char *sha1,
|
|||
struct strbuf *base,
|
||||
const char *pathname, unsigned mode, int stage, void *context)
|
||||
{
|
||||
printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
|
||||
FILE *file = context;
|
||||
fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -565,7 +581,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (rev.shown_one)
|
||||
putchar('\n');
|
||||
printf("%stag %s%s\n",
|
||||
fprintf(rev.diffopt.file, "%stag %s%s\n",
|
||||
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
|
||||
t->tag,
|
||||
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
|
||||
|
@ -584,12 +600,12 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
|||
case OBJ_TREE:
|
||||
if (rev.shown_one)
|
||||
putchar('\n');
|
||||
printf("%stree %s%s\n\n",
|
||||
fprintf(rev.diffopt.file, "%stree %s%s\n\n",
|
||||
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
|
||||
name,
|
||||
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
|
||||
read_tree_recursive((struct tree *)o, "", 0, 0, &match_all,
|
||||
show_tree_object, NULL);
|
||||
show_tree_object, rev.diffopt.file);
|
||||
rev.shown_one = 1;
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
|
@ -674,9 +690,9 @@ static int auto_number = 1;
|
|||
|
||||
static char *default_attach = NULL;
|
||||
|
||||
static struct string_list extra_hdr;
|
||||
static struct string_list extra_to;
|
||||
static struct string_list extra_cc;
|
||||
static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
|
||||
static struct string_list extra_to = STRING_LIST_INIT_NODUP;
|
||||
static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
|
||||
|
||||
static void add_header(const char *value)
|
||||
{
|
||||
|
@ -703,6 +719,7 @@ static void add_header(const char *value)
|
|||
static int thread;
|
||||
static int do_signoff;
|
||||
static int base_auto;
|
||||
static char *from;
|
||||
static const char *signature = git_version_string;
|
||||
static const char *signature_file;
|
||||
static int config_cover_letter;
|
||||
|
@ -791,15 +808,25 @@ static int git_format_config(const char *var, const char *value, void *cb)
|
|||
base_auto = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "format.from")) {
|
||||
int b = git_config_maybe_bool(var, value);
|
||||
free(from);
|
||||
if (b < 0)
|
||||
from = xstrdup(value);
|
||||
else if (b)
|
||||
from = xstrdup(git_committer_info(IDENT_NO_DATE));
|
||||
else
|
||||
from = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_log_config(var, value, cb);
|
||||
}
|
||||
|
||||
static FILE *realstdout = NULL;
|
||||
static const char *output_directory = NULL;
|
||||
static int outdir_offset;
|
||||
|
||||
static int reopen_stdout(struct commit *commit, const char *subject,
|
||||
static int open_next_file(struct commit *commit, const char *subject,
|
||||
struct rev_info *rev, int quiet)
|
||||
{
|
||||
struct strbuf filename = STRBUF_INIT;
|
||||
|
@ -821,9 +848,9 @@ static int reopen_stdout(struct commit *commit, const char *subject,
|
|||
fmt_output_subject(&filename, subject, rev);
|
||||
|
||||
if (!quiet)
|
||||
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
|
||||
printf("%s\n", filename.buf + outdir_offset);
|
||||
|
||||
if (freopen(filename.buf, "w", stdout) == NULL)
|
||||
if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL)
|
||||
return error(_("Cannot open patch file %s"), filename.buf);
|
||||
|
||||
strbuf_release(&filename);
|
||||
|
@ -882,15 +909,15 @@ static void gen_message_id(struct rev_info *info, char *base)
|
|||
info->message_id = strbuf_detach(&buf, NULL);
|
||||
}
|
||||
|
||||
static void print_signature(void)
|
||||
static void print_signature(FILE *file)
|
||||
{
|
||||
if (!signature || !*signature)
|
||||
return;
|
||||
|
||||
printf("-- \n%s", signature);
|
||||
fprintf(file, "-- \n%s", signature);
|
||||
if (signature[strlen(signature)-1] != '\n')
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
putc('\n', file);
|
||||
putc('\n', file);
|
||||
}
|
||||
|
||||
static void add_branch_description(struct strbuf *buf, const char *branch_name)
|
||||
|
@ -953,13 +980,13 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
|||
struct pretty_print_context pp = {0};
|
||||
struct commit *head = list[0];
|
||||
|
||||
if (rev->commit_format != CMIT_FMT_EMAIL)
|
||||
if (!cmit_fmt_is_mail(rev->commit_format))
|
||||
die(_("Cover letter needs email format"));
|
||||
|
||||
committer = git_committer_info(0);
|
||||
|
||||
if (!use_stdout &&
|
||||
reopen_stdout(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
|
||||
open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
|
||||
return;
|
||||
|
||||
log_write_email_headers(rev, head, &pp.subject, &pp.after_subject,
|
||||
|
@ -982,7 +1009,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
|||
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
|
||||
pp_remainder(&pp, &msg, &sb, 0);
|
||||
add_branch_description(&sb, branch_name);
|
||||
printf("%s\n", sb.buf);
|
||||
fprintf(rev->diffopt.file, "%s\n", sb.buf);
|
||||
|
||||
strbuf_release(&sb);
|
||||
|
||||
|
@ -991,6 +1018,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
|||
log.wrap = 72;
|
||||
log.in1 = 2;
|
||||
log.in2 = 4;
|
||||
log.file = rev->diffopt.file;
|
||||
for (i = 0; i < nr; i++)
|
||||
shortlog_add_commit(&log, list[i]);
|
||||
|
||||
|
@ -1013,8 +1041,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
|||
diffcore_std(&opts);
|
||||
diff_flush(&opts);
|
||||
|
||||
printf("\n");
|
||||
print_signature();
|
||||
fprintf(rev->diffopt.file, "\n");
|
||||
print_signature(rev->diffopt.file);
|
||||
}
|
||||
|
||||
static const char *clean_message_id(const char *msg_id)
|
||||
|
@ -1315,7 +1343,7 @@ static void prepare_bases(struct base_tree_info *bases,
|
|||
struct object_id *patch_id;
|
||||
if (commit->util)
|
||||
continue;
|
||||
if (commit_patch_id(commit, &diffopt, sha1))
|
||||
if (commit_patch_id(commit, &diffopt, sha1, 0))
|
||||
die(_("cannot get patch id"));
|
||||
ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
|
||||
patch_id = bases->patch_id + bases->nr_patch_id;
|
||||
|
@ -1324,7 +1352,7 @@ static void prepare_bases(struct base_tree_info *bases,
|
|||
}
|
||||
}
|
||||
|
||||
static void print_bases(struct base_tree_info *bases)
|
||||
static void print_bases(struct base_tree_info *bases, FILE *file)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1333,11 +1361,11 @@ static void print_bases(struct base_tree_info *bases)
|
|||
return;
|
||||
|
||||
/* Show the base commit */
|
||||
printf("base-commit: %s\n", oid_to_hex(&bases->base_commit));
|
||||
fprintf(file, "base-commit: %s\n", oid_to_hex(&bases->base_commit));
|
||||
|
||||
/* Show the prerequisite patches */
|
||||
for (i = bases->nr_patch_id - 1; i >= 0; i--)
|
||||
printf("prerequisite-patch-id: %s\n", oid_to_hex(&bases->patch_id[i]));
|
||||
fprintf(file, "prerequisite-patch-id: %s\n", oid_to_hex(&bases->patch_id[i]));
|
||||
|
||||
free(bases->patch_id);
|
||||
bases->nr_patch_id = 0;
|
||||
|
@ -1368,7 +1396,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
int quiet = 0;
|
||||
int reroll_count = -1;
|
||||
char *branch_name = NULL;
|
||||
char *from = NULL;
|
||||
char *base_commit = NULL;
|
||||
struct base_tree_info bases;
|
||||
|
||||
|
@ -1569,6 +1596,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
setup_pager();
|
||||
|
||||
if (output_directory) {
|
||||
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
|
||||
rev.diffopt.use_color = GIT_COLOR_NEVER;
|
||||
if (use_stdout)
|
||||
die(_("standard output, or directory, which one?"));
|
||||
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
|
||||
|
@ -1626,9 +1655,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
get_patch_ids(&rev, &ids);
|
||||
}
|
||||
|
||||
if (!use_stdout)
|
||||
realstdout = xfdopen(xdup(1), "w");
|
||||
|
||||
if (prepare_revision_walk(&rev))
|
||||
die(_("revision walk setup failed"));
|
||||
rev.boundary = 1;
|
||||
|
@ -1693,7 +1719,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
gen_message_id(&rev, "cover");
|
||||
make_cover_letter(&rev, use_stdout,
|
||||
origin, nr, list, branch_name, quiet);
|
||||
print_bases(&bases);
|
||||
print_bases(&bases, rev.diffopt.file);
|
||||
total++;
|
||||
start_number--;
|
||||
}
|
||||
|
@ -1739,7 +1765,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
}
|
||||
|
||||
if (!use_stdout &&
|
||||
reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
|
||||
open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
|
||||
die(_("Failed to create output files"));
|
||||
shown = log_tree_commit(&rev, commit);
|
||||
free_commit_buffer(commit);
|
||||
|
@ -1754,15 +1780,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
rev.shown_one = 0;
|
||||
if (shown) {
|
||||
if (rev.mime_boundary)
|
||||
printf("\n--%s%s--\n\n\n",
|
||||
fprintf(rev.diffopt.file, "\n--%s%s--\n\n\n",
|
||||
mime_boundary_leader,
|
||||
rev.mime_boundary);
|
||||
else
|
||||
print_signature();
|
||||
print_bases(&bases);
|
||||
print_signature(rev.diffopt.file);
|
||||
print_bases(&bases, rev.diffopt.file);
|
||||
}
|
||||
if (!use_stdout)
|
||||
fclose(stdout);
|
||||
fclose(rev.diffopt.file);
|
||||
}
|
||||
free(list);
|
||||
free(branch_name);
|
||||
|
@ -1794,15 +1820,15 @@ static const char * const cherry_usage[] = {
|
|||
};
|
||||
|
||||
static void print_commit(char sign, struct commit *commit, int verbose,
|
||||
int abbrev)
|
||||
int abbrev, FILE *file)
|
||||
{
|
||||
if (!verbose) {
|
||||
printf("%c %s\n", sign,
|
||||
fprintf(file, "%c %s\n", sign,
|
||||
find_unique_abbrev(commit->object.oid.hash, abbrev));
|
||||
} else {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
|
||||
printf("%c %s %s\n", sign,
|
||||
fprintf(file, "%c %s %s\n", sign,
|
||||
find_unique_abbrev(commit->object.oid.hash, abbrev),
|
||||
buf.buf);
|
||||
strbuf_release(&buf);
|
||||
|
@ -1883,7 +1909,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
|
|||
commit = list->item;
|
||||
if (has_commit_patch_id(commit, &ids))
|
||||
sign = '-';
|
||||
print_commit(sign, commit, verbose, abbrev);
|
||||
print_commit(sign, commit, verbose, abbrev, revs.diffopt.file);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,8 @@ static void show_killed_files(struct dir_struct *dir)
|
|||
*/
|
||||
pos = cache_name_pos(ent->name, ent->len);
|
||||
if (0 <= pos)
|
||||
die("bug in show-killed-files");
|
||||
die("BUG: killed-file %.*s not found",
|
||||
ent->len, ent->name);
|
||||
pos = -pos - 1;
|
||||
while (pos < active_nr &&
|
||||
ce_stage(active_cache[pos]))
|
||||
|
|
|
@ -45,6 +45,19 @@ static int is_from_line(const char *line, int len)
|
|||
|
||||
static struct strbuf buf = STRBUF_INIT;
|
||||
static int keep_cr;
|
||||
static int mboxrd;
|
||||
|
||||
static int is_gtfrom(const struct strbuf *buf)
|
||||
{
|
||||
size_t min = strlen(">From ");
|
||||
size_t ngt;
|
||||
|
||||
if (buf->len < min)
|
||||
return 0;
|
||||
|
||||
ngt = strspn(buf->buf, ">");
|
||||
return ngt && starts_with(buf->buf + ngt, "From ");
|
||||
}
|
||||
|
||||
/* Called with the first line (potentially partial)
|
||||
* already in buf[] -- normally that should begin with
|
||||
|
@ -77,6 +90,9 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
|
|||
strbuf_addch(&buf, '\n');
|
||||
}
|
||||
|
||||
if (mboxrd && is_gtfrom(&buf))
|
||||
strbuf_remove(&buf, 0, 1);
|
||||
|
||||
if (fwrite(buf.buf, 1, buf.len, output) != buf.len)
|
||||
die_errno("cannot write output");
|
||||
|
||||
|
@ -271,6 +287,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
|
|||
keep_cr = 1;
|
||||
} else if ( arg[1] == 'o' && arg[2] ) {
|
||||
dir = arg+2;
|
||||
} else if (!strcmp(arg, "--mboxrd")) {
|
||||
mboxrd = 1;
|
||||
} else if ( arg[1] == '-' && !arg[2] ) {
|
||||
argp++; /* -- marks end of options */
|
||||
break;
|
||||
|
|
|
@ -9,10 +9,10 @@ static const char builtin_merge_recursive_usage[] =
|
|||
|
||||
static const char *better_branch_name(const char *branch)
|
||||
{
|
||||
static char githead_env[8 + 40 + 1];
|
||||
static char githead_env[8 + GIT_SHA1_HEXSZ + 1];
|
||||
char *name;
|
||||
|
||||
if (strlen(branch) != 40)
|
||||
if (strlen(branch) != GIT_SHA1_HEXSZ)
|
||||
return branch;
|
||||
xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch);
|
||||
name = getenv(githead_env);
|
||||
|
@ -21,10 +21,10 @@ static const char *better_branch_name(const char *branch)
|
|||
|
||||
int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const unsigned char *bases[21];
|
||||
const struct object_id *bases[21];
|
||||
unsigned bases_count = 0;
|
||||
int i, failed;
|
||||
unsigned char h1[20], h2[20];
|
||||
struct object_id h1, h2;
|
||||
struct merge_options o;
|
||||
struct commit *result;
|
||||
|
||||
|
@ -46,10 +46,10 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
|
|||
continue;
|
||||
}
|
||||
if (bases_count < ARRAY_SIZE(bases)-1) {
|
||||
unsigned char *sha = xmalloc(20);
|
||||
if (get_sha1(argv[i], sha))
|
||||
struct object_id *oid = xmalloc(sizeof(struct object_id));
|
||||
if (get_oid(argv[i], oid))
|
||||
die("Could not parse object '%s'", argv[i]);
|
||||
bases[bases_count++] = sha;
|
||||
bases[bases_count++] = oid;
|
||||
}
|
||||
else
|
||||
warning("Cannot handle more than %d bases. "
|
||||
|
@ -62,9 +62,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
|
|||
o.branch1 = argv[++i];
|
||||
o.branch2 = argv[++i];
|
||||
|
||||
if (get_sha1(o.branch1, h1))
|
||||
if (get_oid(o.branch1, &h1))
|
||||
die("Could not resolve ref '%s'", o.branch1);
|
||||
if (get_sha1(o.branch2, h2))
|
||||
if (get_oid(o.branch2, &h2))
|
||||
die("Could not resolve ref '%s'", o.branch2);
|
||||
|
||||
o.branch1 = better_branch_name(o.branch1);
|
||||
|
@ -73,7 +73,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
|
|||
if (o.verbosity >= 3)
|
||||
printf("Merging %s with %s\n", o.branch1, o.branch2);
|
||||
|
||||
failed = merge_recursive_generic(&o, h1, h2, bases_count, bases, &result);
|
||||
failed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result);
|
||||
if (failed < 0)
|
||||
return 128; /* die() error code */
|
||||
return failed;
|
||||
|
|
|
@ -212,7 +212,7 @@ static struct option builtin_merge_options[] = {
|
|||
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },
|
||||
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
|
||||
OPT_BOOL(0, "verify-signatures", &verify_signatures,
|
||||
N_("Verify that the named commit has a valid GPG signature")),
|
||||
N_("verify that the named commit has a valid GPG signature")),
|
||||
OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
|
||||
N_("merge strategy to use"), option_parse_strategy),
|
||||
OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
|
||||
|
@ -337,15 +337,9 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
|
|||
struct rev_info rev;
|
||||
struct strbuf out = STRBUF_INIT;
|
||||
struct commit_list *j;
|
||||
const char *filename;
|
||||
int fd;
|
||||
struct pretty_print_context ctx = {0};
|
||||
|
||||
printf(_("Squash commit -- not updating HEAD\n"));
|
||||
filename = git_path_squash_msg();
|
||||
fd = open(filename, O_WRONLY | O_CREAT, 0666);
|
||||
if (fd < 0)
|
||||
die_errno(_("Could not write to '%s'"), filename);
|
||||
|
||||
init_revisions(&rev, NULL);
|
||||
rev.ignore_merges = 1;
|
||||
|
@ -372,10 +366,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
|
|||
oid_to_hex(&commit->object.oid));
|
||||
pretty_print_commit(&ctx, commit, &out);
|
||||
}
|
||||
if (write_in_full(fd, out.buf, out.len) != out.len)
|
||||
die_errno(_("Writing SQUASH_MSG"));
|
||||
if (close(fd))
|
||||
die_errno(_("Finishing SQUASH_MSG"));
|
||||
write_file_buf(git_path_squash_msg(), out.buf, out.len);
|
||||
strbuf_release(&out);
|
||||
}
|
||||
|
||||
|
@ -502,7 +493,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
|||
if (ref_exists(truname.buf)) {
|
||||
strbuf_addf(msg,
|
||||
"%s\t\tbranch '%s'%s of .\n",
|
||||
sha1_to_hex(remote_head->object.oid.hash),
|
||||
oid_to_hex(&remote_head->object.oid),
|
||||
truname.buf + 11,
|
||||
(early ? " (early part)" : ""));
|
||||
strbuf_release(&truname);
|
||||
|
@ -516,7 +507,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
|||
desc = merge_remote_util(remote_head);
|
||||
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
|
||||
strbuf_addf(msg, "%s\t\t%s '%s'\n",
|
||||
sha1_to_hex(desc->obj->oid.hash),
|
||||
oid_to_hex(&desc->obj->oid),
|
||||
typename(desc->obj->type),
|
||||
remote);
|
||||
goto cleanup;
|
||||
|
@ -524,7 +515,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
|||
}
|
||||
|
||||
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
|
||||
sha1_to_hex(remote_head->object.oid.hash), remote);
|
||||
oid_to_hex(&remote_head->object.oid), remote);
|
||||
cleanup:
|
||||
strbuf_release(&buf);
|
||||
strbuf_release(&bname);
|
||||
|
@ -683,6 +674,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
|
|||
hold_locked_index(&lock, 1);
|
||||
clean = merge_recursive(&o, head,
|
||||
remoteheads->item, reversed, &result);
|
||||
if (clean < 0)
|
||||
exit(128);
|
||||
if (active_cache_changed &&
|
||||
write_locked_index(&the_index, &lock, COMMIT_LOCK))
|
||||
die (_("unable to write %s"), get_index_file());
|
||||
|
@ -732,18 +725,6 @@ static void add_strategies(const char *string, unsigned attr)
|
|||
|
||||
}
|
||||
|
||||
static void write_merge_msg(struct strbuf *msg)
|
||||
{
|
||||
const char *filename = git_path_merge_msg();
|
||||
int fd = open(filename, O_WRONLY | O_CREAT, 0666);
|
||||
if (fd < 0)
|
||||
die_errno(_("Could not open '%s' for writing"),
|
||||
filename);
|
||||
if (write_in_full(fd, msg->buf, msg->len) != msg->len)
|
||||
die_errno(_("Could not write to '%s'"), filename);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void read_merge_msg(struct strbuf *msg)
|
||||
{
|
||||
const char *filename = git_path_merge_msg();
|
||||
|
@ -777,7 +758,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
|
|||
strbuf_addch(&msg, '\n');
|
||||
if (0 < option_edit)
|
||||
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
|
||||
write_merge_msg(&msg);
|
||||
write_file_buf(git_path_merge_msg(), msg.buf, msg.len);
|
||||
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
|
||||
git_path_merge_msg(), "merge", NULL))
|
||||
abort_commit(remoteheads, NULL);
|
||||
|
@ -940,8 +921,6 @@ static int setup_with_upstream(const char ***argv)
|
|||
|
||||
static void write_merge_state(struct commit_list *remoteheads)
|
||||
{
|
||||
const char *filename;
|
||||
int fd;
|
||||
struct commit_list *j;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
|
@ -955,26 +934,14 @@ static void write_merge_state(struct commit_list *remoteheads)
|
|||
}
|
||||
strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
|
||||
}
|
||||
filename = git_path_merge_head();
|
||||
fd = open(filename, O_WRONLY | O_CREAT, 0666);
|
||||
if (fd < 0)
|
||||
die_errno(_("Could not open '%s' for writing"), filename);
|
||||
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
|
||||
die_errno(_("Could not write to '%s'"), filename);
|
||||
close(fd);
|
||||
write_file_buf(git_path_merge_head(), buf.buf, buf.len);
|
||||
strbuf_addch(&merge_msg, '\n');
|
||||
write_merge_msg(&merge_msg);
|
||||
write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len);
|
||||
|
||||
filename = git_path_merge_mode();
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
die_errno(_("Could not open '%s' for writing"), filename);
|
||||
strbuf_reset(&buf);
|
||||
if (fast_forward == FF_NO)
|
||||
strbuf_addf(&buf, "no-ff");
|
||||
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
|
||||
die_errno(_("Could not write to '%s'"), filename);
|
||||
close(fd);
|
||||
write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
|
||||
}
|
||||
|
||||
static int default_edit_option(void)
|
||||
|
@ -990,7 +957,7 @@ static int default_edit_option(void)
|
|||
if (e) {
|
||||
int v = git_config_maybe_bool(name, e);
|
||||
if (v < 0)
|
||||
die("Bad value '%s' in environment '%s'", e, name);
|
||||
die(_("Bad value '%s' in environment '%s'"), e, name);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -1091,7 +1058,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
|
|||
if (!commit) {
|
||||
if (ptr)
|
||||
*ptr = '\0';
|
||||
die("not something we can merge in %s: %s",
|
||||
die(_("not something we can merge in %s: %s"),
|
||||
filename, merge_names->buf + pos);
|
||||
}
|
||||
remotes = &commit_list_insert(commit, remotes)->next;
|
||||
|
@ -1125,7 +1092,7 @@ static struct commit_list *collect_parents(struct commit *head_commit,
|
|||
struct commit *commit = get_merge_parent(argv[i]);
|
||||
if (!commit)
|
||||
help_unknown_ref(argv[i], "merge",
|
||||
"not something we can merge");
|
||||
_("not something we can merge"));
|
||||
remotes = &commit_list_insert(commit, remotes)->next;
|
||||
}
|
||||
remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
|
||||
|
@ -1342,7 +1309,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
|||
for (p = remoteheads; p; p = p->next) {
|
||||
struct commit *commit = p->item;
|
||||
strbuf_addf(&buf, "GITHEAD_%s",
|
||||
sha1_to_hex(commit->object.oid.hash));
|
||||
oid_to_hex(&commit->object.oid));
|
||||
setenv(buf.buf, merge_remote_util(commit)->name, 1);
|
||||
strbuf_reset(&buf);
|
||||
if (fast_forward != FF_ONLY &&
|
||||
|
@ -1397,11 +1364,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
|||
* If head can reach all the merge then we are up to date.
|
||||
* but first the most common case of merging one remote.
|
||||
*/
|
||||
finish_up_to_date("Already up-to-date.");
|
||||
finish_up_to_date(_("Already up-to-date."));
|
||||
goto done;
|
||||
} else if (fast_forward != FF_NO && !remoteheads->next &&
|
||||
!common->next &&
|
||||
!hashcmp(common->item->object.oid.hash, head_commit->object.oid.hash)) {
|
||||
!oidcmp(&common->item->object.oid, &head_commit->object.oid)) {
|
||||
/* Again the most common case of merging one remote. */
|
||||
struct strbuf msg = STRBUF_INIT;
|
||||
struct commit *commit;
|
||||
|
@ -1475,14 +1442,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
|||
* HEAD^^" would be missed.
|
||||
*/
|
||||
common_one = get_merge_bases(head_commit, j->item);
|
||||
if (hashcmp(common_one->item->object.oid.hash,
|
||||
j->item->object.oid.hash)) {
|
||||
if (oidcmp(&common_one->item->object.oid, &j->item->object.oid)) {
|
||||
up_to_date = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (up_to_date) {
|
||||
finish_up_to_date("Already up-to-date. Yeeah!");
|
||||
finish_up_to_date(_("Already up-to-date. Yeeah!"));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
@ -1506,7 +1472,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
|||
* Stash away the local changes so that we can try more than one.
|
||||
*/
|
||||
save_state(stash))
|
||||
hashcpy(stash, null_sha1);
|
||||
hashclr(stash);
|
||||
|
||||
for (i = 0; i < use_strategies_nr; i++) {
|
||||
int ret;
|
||||
|
|
|
@ -91,7 +91,7 @@ static const char * const git_notes_get_ref_usage[] = {
|
|||
};
|
||||
|
||||
static const char note_template[] =
|
||||
"\nWrite/edit the notes for the following object:\n";
|
||||
N_("Write/edit the notes for the following object:");
|
||||
|
||||
struct note_data {
|
||||
int given;
|
||||
|
@ -179,7 +179,8 @@ static void prepare_note_data(const unsigned char *object, struct note_data *d,
|
|||
copy_obj_to_fd(fd, old_note);
|
||||
|
||||
strbuf_addch(&buf, '\n');
|
||||
strbuf_add_commented_lines(&buf, note_template, strlen(note_template));
|
||||
strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
|
||||
strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));
|
||||
strbuf_addch(&buf, '\n');
|
||||
write_or_die(fd, buf.buf, buf.len);
|
||||
|
||||
|
@ -749,7 +750,7 @@ static int git_config_get_notes_strategy(const char *key,
|
|||
if (git_config_get_string(key, &value))
|
||||
return 1;
|
||||
if (parse_notes_merge_strategy(value, strategy))
|
||||
git_die_config(key, "unknown notes merge strategy %s", value);
|
||||
git_die_config(key, _("unknown notes merge strategy %s"), value);
|
||||
|
||||
free(value);
|
||||
return 0;
|
||||
|
@ -788,15 +789,15 @@ static int merge(int argc, const char **argv, const char *prefix)
|
|||
if (strategy || do_commit + do_abort == 0)
|
||||
do_merge = 1;
|
||||
if (do_merge + do_commit + do_abort != 1) {
|
||||
error("cannot mix --commit, --abort or -s/--strategy");
|
||||
error(_("cannot mix --commit, --abort or -s/--strategy"));
|
||||
usage_with_options(git_notes_merge_usage, options);
|
||||
}
|
||||
|
||||
if (do_merge && argc != 1) {
|
||||
error("Must specify a notes ref to merge");
|
||||
error(_("Must specify a notes ref to merge"));
|
||||
usage_with_options(git_notes_merge_usage, options);
|
||||
} else if (!do_merge && argc) {
|
||||
error("too many parameters");
|
||||
error(_("too many parameters"));
|
||||
usage_with_options(git_notes_merge_usage, options);
|
||||
}
|
||||
|
||||
|
@ -817,7 +818,7 @@ static int merge(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (strategy) {
|
||||
if (parse_notes_merge_strategy(strategy, &o.strategy)) {
|
||||
error("Unknown -s/--strategy: %s", strategy);
|
||||
error(_("Unknown -s/--strategy: %s"), strategy);
|
||||
usage_with_options(git_notes_merge_usage, options);
|
||||
}
|
||||
} else {
|
||||
|
@ -857,11 +858,11 @@ static int merge(int argc, const char **argv, const char *prefix)
|
|||
die(_("A notes merge into %s is already in-progress at %s"),
|
||||
default_notes_ref(), wt->path);
|
||||
if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
|
||||
die("Failed to store link to current notes ref (%s)",
|
||||
die(_("Failed to store link to current notes ref (%s)"),
|
||||
default_notes_ref());
|
||||
printf("Automatic notes merge failed. Fix conflicts in %s and "
|
||||
"commit the result with 'git notes merge --commit', or "
|
||||
"abort the merge with 'git notes merge --abort'.\n",
|
||||
printf(_("Automatic notes merge failed. Fix conflicts in %s and "
|
||||
"commit the result with 'git notes merge --commit', or "
|
||||
"abort the merge with 'git notes merge --abort'.\n"),
|
||||
git_path(NOTES_MERGE_WORKTREE));
|
||||
}
|
||||
|
||||
|
@ -934,8 +935,8 @@ static int prune(int argc, const char **argv, const char *prefix)
|
|||
struct notes_tree *t;
|
||||
int show_only = 0, verbose = 0;
|
||||
struct option options[] = {
|
||||
OPT__DRY_RUN(&show_only, "do not remove, show only"),
|
||||
OPT__VERBOSE(&verbose, "report pruned notes"),
|
||||
OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
|
||||
OPT__VERBOSE(&verbose, N_("report pruned notes")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -964,7 +965,7 @@ static int get_ref(int argc, const char **argv, const char *prefix)
|
|||
git_notes_get_ref_usage, 0);
|
||||
|
||||
if (argc) {
|
||||
error("too many parameters");
|
||||
error(_("too many parameters"));
|
||||
usage_with_options(git_notes_get_ref_usage, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ static int non_empty;
|
|||
static int reuse_delta = 1, reuse_object = 1;
|
||||
static int keep_unreachable, unpack_unreachable, include_tag;
|
||||
static unsigned long unpack_unreachable_expiration;
|
||||
static int pack_loose_unreachable;
|
||||
static int local;
|
||||
static int have_non_local_packs;
|
||||
static int incremental;
|
||||
static int ignore_packed_keep;
|
||||
static int allow_ofs_delta;
|
||||
|
@ -977,6 +979,23 @@ static int want_object_in_pack(const unsigned char *sha1,
|
|||
return 1;
|
||||
if (incremental)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* When asked to do --local (do not include an
|
||||
* object that appears in a pack we borrow
|
||||
* from elsewhere) or --honor-pack-keep (do not
|
||||
* include an object that appears in a pack marked
|
||||
* with .keep), we need to make sure no copy of this
|
||||
* object come from in _any_ pack that causes us to
|
||||
* omit it, and need to complete this loop. When
|
||||
* neither option is in effect, we know the object
|
||||
* we just found is going to be packed, so break
|
||||
* out of the loop to return 1 now.
|
||||
*/
|
||||
if (!ignore_packed_keep &&
|
||||
(!local || !have_non_local_packs))
|
||||
break;
|
||||
|
||||
if (local && !p->pack_local)
|
||||
return 0;
|
||||
if (ignore_packed_keep && p->pack_local && p->pack_keep)
|
||||
|
@ -2379,6 +2398,32 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
|
|||
free(in_pack.array);
|
||||
}
|
||||
|
||||
static int add_loose_object(const unsigned char *sha1, const char *path,
|
||||
void *data)
|
||||
{
|
||||
enum object_type type = sha1_object_info(sha1, NULL);
|
||||
|
||||
if (type < 0) {
|
||||
warning("loose object at %s could not be examined", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_object_entry(sha1, type, "", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We actually don't even have to worry about reachability here.
|
||||
* add_object_entry will weed out duplicates, so we just add every
|
||||
* loose object we find.
|
||||
*/
|
||||
static void add_unreachable_loose_objects(void)
|
||||
{
|
||||
for_each_loose_file_in_objdir(get_object_directory(),
|
||||
add_loose_object,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
|
||||
{
|
||||
static struct packed_git *last_found = (void *)1;
|
||||
|
@ -2548,6 +2593,8 @@ static void get_object_list(int ac, const char **av)
|
|||
|
||||
if (keep_unreachable)
|
||||
add_objects_in_unpacked_packs(&revs);
|
||||
if (pack_loose_unreachable)
|
||||
add_unreachable_loose_objects();
|
||||
if (unpack_unreachable)
|
||||
loosen_unused_packed_objects(&revs);
|
||||
|
||||
|
@ -2648,6 +2695,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||
N_("include tag objects that refer to objects to be packed")),
|
||||
OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
|
||||
N_("keep unreachable objects")),
|
||||
OPT_BOOL(0, "pack-loose-unreachable", &pack_loose_unreachable,
|
||||
N_("pack loose unreachable objects")),
|
||||
{ OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
|
||||
N_("unpack unreachable objects newer than <time>"),
|
||||
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
|
||||
|
@ -2753,6 +2802,28 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||
progress = 2;
|
||||
|
||||
prepare_packed_git();
|
||||
if (ignore_packed_keep) {
|
||||
struct packed_git *p;
|
||||
for (p = packed_git; p; p = p->next)
|
||||
if (p->pack_local && p->pack_keep)
|
||||
break;
|
||||
if (!p) /* no keep-able packs found */
|
||||
ignore_packed_keep = 0;
|
||||
}
|
||||
if (local) {
|
||||
/*
|
||||
* unlike ignore_packed_keep above, we do not want to
|
||||
* unset "local" based on looking at packs, as it
|
||||
* also covers non-local objects
|
||||
*/
|
||||
struct packed_git *p;
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
if (!p->pack_local) {
|
||||
have_non_local_packs = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
progress_state = start_progress(_("Counting objects"), 0);
|
||||
|
|
|
@ -815,6 +815,9 @@ static int run_rebase(const unsigned char *curr_head,
|
|||
argv_array_push(&args, "--no-autostash");
|
||||
else if (opt_autostash == 1)
|
||||
argv_array_push(&args, "--autostash");
|
||||
if (opt_verify_signatures &&
|
||||
!strcmp(opt_verify_signatures, "--verify-signatures"))
|
||||
warning(_("ignoring --verify-signatures for rebase"));
|
||||
|
||||
argv_array_push(&args, "--onto");
|
||||
argv_array_push(&args, sha1_to_hex(merge_head));
|
||||
|
@ -852,7 +855,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
|
|||
git_config(git_pull_config, NULL);
|
||||
|
||||
if (read_cache_unmerged())
|
||||
die_resolve_conflict("Pull");
|
||||
die_resolve_conflict("pull");
|
||||
|
||||
if (file_exists(git_path("MERGE_HEAD")))
|
||||
die_conclude_merge();
|
||||
|
|
|
@ -353,7 +353,8 @@ static int push_with_options(struct transport *transport, int flags)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int do_push(const char *repo, int flags)
|
||||
static int do_push(const char *repo, int flags,
|
||||
const struct string_list *push_options)
|
||||
{
|
||||
int i, errs;
|
||||
struct remote *remote = pushremote_get(repo);
|
||||
|
@ -376,6 +377,9 @@ static int do_push(const char *repo, int flags)
|
|||
if (remote->mirror)
|
||||
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
|
||||
|
||||
if (push_options->nr)
|
||||
flags |= TRANSPORT_PUSH_OPTIONS;
|
||||
|
||||
if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
|
||||
if (!strcmp(*refspec, "refs/tags/*"))
|
||||
return error(_("--all and --tags are incompatible"));
|
||||
|
@ -406,13 +410,16 @@ static int do_push(const char *repo, int flags)
|
|||
for (i = 0; i < url_nr; i++) {
|
||||
struct transport *transport =
|
||||
transport_get(remote, url[i]);
|
||||
if (flags & TRANSPORT_PUSH_OPTIONS)
|
||||
transport->push_options = push_options;
|
||||
if (push_with_options(transport, flags))
|
||||
errs++;
|
||||
}
|
||||
} else {
|
||||
struct transport *transport =
|
||||
transport_get(remote, NULL);
|
||||
|
||||
if (flags & TRANSPORT_PUSH_OPTIONS)
|
||||
transport->push_options = push_options;
|
||||
if (push_with_options(transport, flags))
|
||||
errs++;
|
||||
}
|
||||
|
@ -500,6 +507,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
|||
int push_cert = -1;
|
||||
int rc;
|
||||
const char *repo = NULL; /* default repository */
|
||||
static struct string_list push_options = STRING_LIST_INIT_DUP;
|
||||
static struct string_list_item *item;
|
||||
|
||||
struct option options[] = {
|
||||
OPT__VERBOSITY(&verbosity),
|
||||
OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
|
||||
|
@ -533,6 +543,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
|||
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
|
||||
PARSE_OPT_OPTARG, option_parse_push_signed },
|
||||
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
|
||||
OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
|
||||
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
|
||||
TRANSPORT_FAMILY_IPV4),
|
||||
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
|
||||
|
@ -563,7 +574,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
|||
set_refspecs(argv + 1, argc - 1, repo);
|
||||
}
|
||||
|
||||
rc = do_push(repo, flags);
|
||||
for_each_string_list_item(item, &push_options)
|
||||
if (strchr(item->string, '\n'))
|
||||
die(_("push options must not have new line characters"));
|
||||
|
||||
rc = do_push(repo, flags, &push_options);
|
||||
if (rc == -1)
|
||||
usage_with_options(push_usage, options);
|
||||
else
|
||||
|
|
|
@ -44,10 +44,12 @@ static struct strbuf fsck_msg_types = STRBUF_INIT;
|
|||
static int receive_unpack_limit = -1;
|
||||
static int transfer_unpack_limit = -1;
|
||||
static int advertise_atomic_push = 1;
|
||||
static int advertise_push_options;
|
||||
static int unpack_limit = 100;
|
||||
static int report_status;
|
||||
static int use_sideband;
|
||||
static int use_atomic;
|
||||
static int use_push_options;
|
||||
static int quiet;
|
||||
static int prefer_ofs_delta = 1;
|
||||
static int auto_update_server_info;
|
||||
|
@ -76,6 +78,13 @@ static long nonce_stamp_slop;
|
|||
static unsigned long nonce_stamp_slop_limit;
|
||||
static struct ref_transaction *transaction;
|
||||
|
||||
static enum {
|
||||
KEEPALIVE_NEVER = 0,
|
||||
KEEPALIVE_AFTER_NUL,
|
||||
KEEPALIVE_ALWAYS
|
||||
} use_keepalive;
|
||||
static int keepalive_in_sec = 5;
|
||||
|
||||
static enum deny_action parse_deny_action(const char *var, const char *value)
|
||||
{
|
||||
if (value) {
|
||||
|
@ -193,6 +202,16 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(var, "receive.advertisepushoptions") == 0) {
|
||||
advertise_push_options = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(var, "receive.keepalive") == 0) {
|
||||
keepalive_in_sec = git_config_int(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
|
@ -211,6 +230,8 @@ static void show_ref(const char *path, const unsigned char *sha1)
|
|||
strbuf_addstr(&cap, " ofs-delta");
|
||||
if (push_cert_nonce)
|
||||
strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
|
||||
if (advertise_push_options)
|
||||
strbuf_addstr(&cap, " push-options");
|
||||
strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
|
||||
packet_write(1, "%s %s%c%s\n",
|
||||
sha1_to_hex(sha1), path, 0, cap.buf);
|
||||
|
@ -319,10 +340,60 @@ static void rp_error(const char *err, ...)
|
|||
static int copy_to_sideband(int in, int out, void *arg)
|
||||
{
|
||||
char data[128];
|
||||
int keepalive_active = 0;
|
||||
|
||||
if (keepalive_in_sec <= 0)
|
||||
use_keepalive = KEEPALIVE_NEVER;
|
||||
if (use_keepalive == KEEPALIVE_ALWAYS)
|
||||
keepalive_active = 1;
|
||||
|
||||
while (1) {
|
||||
ssize_t sz = xread(in, data, sizeof(data));
|
||||
ssize_t sz;
|
||||
|
||||
if (keepalive_active) {
|
||||
struct pollfd pfd;
|
||||
int ret;
|
||||
|
||||
pfd.fd = in;
|
||||
pfd.events = POLLIN;
|
||||
ret = poll(&pfd, 1, 1000 * keepalive_in_sec);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
} else if (ret == 0) {
|
||||
/* no data; send a keepalive packet */
|
||||
static const char buf[] = "0005\1";
|
||||
write_or_die(1, buf, sizeof(buf) - 1);
|
||||
continue;
|
||||
} /* else there is actual data to read */
|
||||
}
|
||||
|
||||
sz = xread(in, data, sizeof(data));
|
||||
if (sz <= 0)
|
||||
break;
|
||||
|
||||
if (use_keepalive == KEEPALIVE_AFTER_NUL && !keepalive_active) {
|
||||
const char *p = memchr(data, '\0', sz);
|
||||
if (p) {
|
||||
/*
|
||||
* The NUL tells us to start sending keepalives. Make
|
||||
* sure we send any other data we read along
|
||||
* with it.
|
||||
*/
|
||||
keepalive_active = 1;
|
||||
send_sideband(1, 2, data, p - data, use_sideband);
|
||||
send_sideband(1, 2, p + 1, sz - (p - data + 1), use_sideband);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Either we're not looking for a NUL signal, or we didn't see
|
||||
* it yet; just pass along the data.
|
||||
*/
|
||||
send_sideband(1, 2, data, sz, use_sideband);
|
||||
}
|
||||
close(in);
|
||||
|
@ -550,8 +621,16 @@ static void prepare_push_cert_sha1(struct child_process *proc)
|
|||
}
|
||||
}
|
||||
|
||||
struct receive_hook_feed_state {
|
||||
struct command *cmd;
|
||||
int skip_broken;
|
||||
struct strbuf buf;
|
||||
const struct string_list *push_options;
|
||||
};
|
||||
|
||||
typedef int (*feed_fn)(void *, const char **, size_t *);
|
||||
static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
|
||||
static int run_and_feed_hook(const char *hook_name, feed_fn feed,
|
||||
struct receive_hook_feed_state *feed_state)
|
||||
{
|
||||
struct child_process proc = CHILD_PROCESS_INIT;
|
||||
struct async muxer;
|
||||
|
@ -567,6 +646,16 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
|
|||
proc.argv = argv;
|
||||
proc.in = -1;
|
||||
proc.stdout_to_stderr = 1;
|
||||
if (feed_state->push_options) {
|
||||
int i;
|
||||
for (i = 0; i < feed_state->push_options->nr; i++)
|
||||
argv_array_pushf(&proc.env_array,
|
||||
"GIT_PUSH_OPTION_%d=%s", i,
|
||||
feed_state->push_options->items[i].string);
|
||||
argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d",
|
||||
feed_state->push_options->nr);
|
||||
} else
|
||||
argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
|
||||
|
||||
if (use_sideband) {
|
||||
memset(&muxer, 0, sizeof(muxer));
|
||||
|
@ -606,12 +695,6 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
|
|||
return finish_command(&proc);
|
||||
}
|
||||
|
||||
struct receive_hook_feed_state {
|
||||
struct command *cmd;
|
||||
int skip_broken;
|
||||
struct strbuf buf;
|
||||
};
|
||||
|
||||
static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
|
||||
{
|
||||
struct receive_hook_feed_state *state = state_;
|
||||
|
@ -634,8 +717,10 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int run_receive_hook(struct command *commands, const char *hook_name,
|
||||
int skip_broken)
|
||||
static int run_receive_hook(struct command *commands,
|
||||
const char *hook_name,
|
||||
int skip_broken,
|
||||
const struct string_list *push_options)
|
||||
{
|
||||
struct receive_hook_feed_state state;
|
||||
int status;
|
||||
|
@ -646,6 +731,7 @@ static int run_receive_hook(struct command *commands, const char *hook_name,
|
|||
if (feed_receive_hook(&state, NULL, NULL))
|
||||
return 0;
|
||||
state.cmd = commands;
|
||||
state.push_options = push_options;
|
||||
status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
|
||||
strbuf_release(&state.buf);
|
||||
return status;
|
||||
|
@ -737,7 +823,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
|
|||
{
|
||||
static struct lock_file shallow_lock;
|
||||
struct sha1_array extra = SHA1_ARRAY_INIT;
|
||||
const char *alt_file;
|
||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||
uint32_t mask = 1 << (cmd->index % 32);
|
||||
int i;
|
||||
|
||||
|
@ -749,9 +835,8 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
|
|||
!delayed_reachability_test(si, i))
|
||||
sha1_array_append(&extra, si->shallow->sha1[i]);
|
||||
|
||||
setup_alternate_shallow(&shallow_lock, &alt_file, &extra);
|
||||
if (check_shallow_connected(command_singleton_iterator,
|
||||
0, cmd, alt_file)) {
|
||||
setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra);
|
||||
if (check_connected(command_singleton_iterator, cmd, &opt)) {
|
||||
rollback_lock_file(&shallow_lock);
|
||||
sha1_array_clear(&extra);
|
||||
return -1;
|
||||
|
@ -1160,8 +1245,8 @@ static void set_connectivity_errors(struct command *commands,
|
|||
if (shallow_update && si->shallow_ref[cmd->index])
|
||||
/* to be checked in update_shallow_ref() */
|
||||
continue;
|
||||
if (!check_everything_connected(command_singleton_iterator,
|
||||
0, &singleton))
|
||||
if (!check_connected(command_singleton_iterator, &singleton,
|
||||
NULL))
|
||||
continue;
|
||||
cmd->error_string = "missing necessary objects";
|
||||
}
|
||||
|
@ -1316,11 +1401,15 @@ cleanup:
|
|||
|
||||
static void execute_commands(struct command *commands,
|
||||
const char *unpacker_error,
|
||||
struct shallow_info *si)
|
||||
struct shallow_info *si,
|
||||
const struct string_list *push_options)
|
||||
{
|
||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||
struct command *cmd;
|
||||
unsigned char sha1[20];
|
||||
struct iterate_data data;
|
||||
struct async muxer;
|
||||
int err_fd = 0;
|
||||
|
||||
if (unpacker_error) {
|
||||
for (cmd = commands; cmd; cmd = cmd->next)
|
||||
|
@ -1328,14 +1417,28 @@ static void execute_commands(struct command *commands,
|
|||
return;
|
||||
}
|
||||
|
||||
if (use_sideband) {
|
||||
memset(&muxer, 0, sizeof(muxer));
|
||||
muxer.proc = copy_to_sideband;
|
||||
muxer.in = -1;
|
||||
if (!start_async(&muxer))
|
||||
err_fd = muxer.in;
|
||||
/* ...else, continue without relaying sideband */
|
||||
}
|
||||
|
||||
data.cmds = commands;
|
||||
data.si = si;
|
||||
if (check_everything_connected(iterate_receive_command_list, 0, &data))
|
||||
opt.err_fd = err_fd;
|
||||
opt.progress = err_fd && !quiet;
|
||||
if (check_connected(iterate_receive_command_list, &data, &opt))
|
||||
set_connectivity_errors(commands, si);
|
||||
|
||||
if (use_sideband)
|
||||
finish_async(&muxer);
|
||||
|
||||
reject_updates_to_hidden(commands);
|
||||
|
||||
if (run_receive_hook(commands, "pre-receive", 0)) {
|
||||
if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string)
|
||||
cmd->error_string = "pre-receive hook declined";
|
||||
|
@ -1437,6 +1540,9 @@ static struct command *read_head_info(struct sha1_array *shallow)
|
|||
if (advertise_atomic_push
|
||||
&& parse_feature_request(feature_list, "atomic"))
|
||||
use_atomic = 1;
|
||||
if (advertise_push_options
|
||||
&& parse_feature_request(feature_list, "push-options"))
|
||||
use_push_options = 1;
|
||||
}
|
||||
|
||||
if (!strcmp(line, "push-cert")) {
|
||||
|
@ -1469,6 +1575,21 @@ static struct command *read_head_info(struct sha1_array *shallow)
|
|||
return commands;
|
||||
}
|
||||
|
||||
static void read_push_options(struct string_list *options)
|
||||
{
|
||||
while (1) {
|
||||
char *line;
|
||||
int len;
|
||||
|
||||
line = packet_read_line(0, &len);
|
||||
|
||||
if (!line)
|
||||
break;
|
||||
|
||||
string_list_append(options, line);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *parse_pack_header(struct pack_header *hdr)
|
||||
{
|
||||
switch (read_pack_header(0, hdr)) {
|
||||
|
@ -1546,6 +1667,10 @@ static const char *unpack(int err_fd, struct shallow_info *si)
|
|||
(uintmax_t)getpid(),
|
||||
hostname);
|
||||
|
||||
if (!quiet && err_fd)
|
||||
argv_array_push(&child.args, "--show-resolving-progress");
|
||||
if (use_sideband)
|
||||
argv_array_push(&child.args, "--report-end-of-input");
|
||||
if (fsck_objects)
|
||||
argv_array_pushf(&child.args, "--strict%s",
|
||||
fsck_msg_types.buf);
|
||||
|
@ -1575,6 +1700,7 @@ static const char *unpack_with_sideband(struct shallow_info *si)
|
|||
if (!use_sideband)
|
||||
return unpack(0, si);
|
||||
|
||||
use_keepalive = KEEPALIVE_AFTER_NUL;
|
||||
memset(&muxer, 0, sizeof(muxer));
|
||||
muxer.proc = copy_to_sideband;
|
||||
muxer.in = -1;
|
||||
|
@ -1754,6 +1880,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if ((commands = read_head_info(&shallow)) != NULL) {
|
||||
const char *unpack_status = NULL;
|
||||
struct string_list push_options = STRING_LIST_INIT_DUP;
|
||||
|
||||
if (use_push_options)
|
||||
read_push_options(&push_options);
|
||||
|
||||
prepare_shallow_info(&si, &shallow);
|
||||
if (!si.nr_ours && !si.nr_theirs)
|
||||
|
@ -1762,20 +1892,36 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
|
|||
unpack_status = unpack_with_sideband(&si);
|
||||
update_shallow_info(commands, &si, &ref);
|
||||
}
|
||||
execute_commands(commands, unpack_status, &si);
|
||||
use_keepalive = KEEPALIVE_ALWAYS;
|
||||
execute_commands(commands, unpack_status, &si,
|
||||
&push_options);
|
||||
if (pack_lockfile)
|
||||
unlink_or_warn(pack_lockfile);
|
||||
if (report_status)
|
||||
report(commands, unpack_status);
|
||||
run_receive_hook(commands, "post-receive", 1);
|
||||
run_receive_hook(commands, "post-receive", 1,
|
||||
&push_options);
|
||||
run_update_post_hook(commands);
|
||||
if (push_options.nr)
|
||||
string_list_clear(&push_options, 0);
|
||||
if (auto_gc) {
|
||||
const char *argv_gc_auto[] = {
|
||||
"gc", "--auto", "--quiet", NULL,
|
||||
};
|
||||
int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
|
||||
struct child_process proc = CHILD_PROCESS_INIT;
|
||||
|
||||
proc.no_stdin = 1;
|
||||
proc.stdout_to_stderr = 1;
|
||||
proc.err = use_sideband ? -1 : 0;
|
||||
proc.git_cmd = 1;
|
||||
proc.argv = argv_gc_auto;
|
||||
|
||||
close_all_packs();
|
||||
run_command_v_opt(argv_gc_auto, opt);
|
||||
if (!start_command(&proc)) {
|
||||
if (use_sideband)
|
||||
copy_to_sideband(proc.err, -1, NULL);
|
||||
finish_command(&proc);
|
||||
}
|
||||
}
|
||||
if (auto_update_server_info)
|
||||
update_server_info(0);
|
||||
|
|
|
@ -247,7 +247,7 @@ struct branch_info {
|
|||
enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
|
||||
};
|
||||
|
||||
static struct string_list branch_list;
|
||||
static struct string_list branch_list = STRING_LIST_INIT_NODUP;
|
||||
|
||||
static const char *abbrev_ref(const char *name, const char *prefix)
|
||||
{
|
||||
|
@ -539,10 +539,6 @@ static int add_branch_for_removal(const char *refname,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* make sure that symrefs are deleted */
|
||||
if (flags & REF_ISSYMREF)
|
||||
return unlink(git_path("%s", refname));
|
||||
|
||||
string_list_append(branches->branches, refname);
|
||||
|
||||
return 0;
|
||||
|
@ -788,7 +784,7 @@ static int rm(int argc, const char **argv)
|
|||
strbuf_release(&buf);
|
||||
|
||||
if (!result)
|
||||
result = delete_refs(&branches);
|
||||
result = delete_refs(&branches, REF_NODEREF);
|
||||
string_list_clear(&branches, 0);
|
||||
|
||||
if (skipped.nr) {
|
||||
|
@ -952,7 +948,7 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
|
|||
struct show_info *show_info = cb_data;
|
||||
struct branch_info *branch_info = item->util;
|
||||
struct string_list *merge = &branch_info->merge;
|
||||
const char *also;
|
||||
int width = show_info->width + 4;
|
||||
int i;
|
||||
|
||||
if (branch_info->rebase && branch_info->merge.nr > 1) {
|
||||
|
@ -963,19 +959,18 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
|
|||
|
||||
printf(" %-*s ", show_info->width, item->string);
|
||||
if (branch_info->rebase) {
|
||||
printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?
|
||||
"rebases interactively onto remote %s" :
|
||||
"rebases onto remote %s"), merge->items[0].string);
|
||||
printf_ln(branch_info->rebase == INTERACTIVE_REBASE
|
||||
? _("rebases interactively onto remote %s")
|
||||
: _("rebases onto remote %s"), merge->items[0].string);
|
||||
return 0;
|
||||
} else if (show_info->any_rebase) {
|
||||
printf_ln(_(" merges with remote %s"), merge->items[0].string);
|
||||
also = _(" and with remote");
|
||||
width++;
|
||||
} else {
|
||||
printf_ln(_("merges with remote %s"), merge->items[0].string);
|
||||
also = _(" and with remote");
|
||||
}
|
||||
for (i = 1; i < merge->nr; i++)
|
||||
printf(" %-*s %s %s\n", show_info->width, "", also,
|
||||
printf(_("%-*s and with remote %s\n"), width, "",
|
||||
merge->items[i].string);
|
||||
|
||||
return 0;
|
||||
|
@ -1158,11 +1153,11 @@ static int show(int argc, const char **argv)
|
|||
the one in " Fetch URL: %s" translation */
|
||||
printf_ln(_(" Push URL: %s"), url[i]);
|
||||
if (!i)
|
||||
printf_ln(_(" Push URL: %s"), "(no URL)");
|
||||
printf_ln(_(" Push URL: %s"), _("(no URL)"));
|
||||
if (no_query)
|
||||
printf_ln(_(" HEAD branch: %s"), "(not queried)");
|
||||
printf_ln(_(" HEAD branch: %s"), _("(not queried)"));
|
||||
else if (!states.heads.nr)
|
||||
printf_ln(_(" HEAD branch: %s"), "(unknown)");
|
||||
printf_ln(_(" HEAD branch: %s"), _("(unknown)"));
|
||||
else if (states.heads.nr == 1)
|
||||
printf_ln(_(" HEAD branch: %s"), states.heads.items[0].string);
|
||||
else {
|
||||
|
@ -1305,7 +1300,7 @@ static int prune_remote(const char *remote, int dry_run)
|
|||
string_list_sort(&refs_to_prune);
|
||||
|
||||
if (!dry_run)
|
||||
result |= delete_refs(&refs_to_prune);
|
||||
result |= delete_refs(&refs_to_prune, 0);
|
||||
|
||||
for_each_string_list_item(item, &states.stale) {
|
||||
const char *refname = item->util;
|
||||
|
|
|
@ -146,6 +146,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
int pack_everything = 0;
|
||||
int delete_redundant = 0;
|
||||
const char *unpack_unreachable = NULL;
|
||||
int keep_unreachable = 0;
|
||||
const char *window = NULL, *window_memory = NULL;
|
||||
const char *depth = NULL;
|
||||
const char *max_pack_size = NULL;
|
||||
|
@ -175,6 +176,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
N_("write bitmap index")),
|
||||
OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
|
||||
N_("with -A, do not loosen objects older than this")),
|
||||
OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
|
||||
N_("with -a, repack unreachable objects")),
|
||||
OPT_STRING(0, "window", &window, N_("n"),
|
||||
N_("size of the window used for delta compression")),
|
||||
OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
|
||||
|
@ -196,6 +199,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
if (delete_redundant && repository_format_precious_objects)
|
||||
die(_("cannot delete packs in a precious-objects repo"));
|
||||
|
||||
if (keep_unreachable &&
|
||||
(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
|
||||
die(_("--keep-unreachable and -A are incompatible"));
|
||||
|
||||
if (pack_kept_objects < 0)
|
||||
pack_kept_objects = write_bitmaps;
|
||||
|
||||
|
@ -239,6 +246,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
} else if (pack_everything & LOOSEN_UNREACHABLE) {
|
||||
argv_array_push(&cmd.args,
|
||||
"--unpack-unreachable");
|
||||
} else if (keep_unreachable) {
|
||||
argv_array_push(&cmd.args, "--keep-unreachable");
|
||||
argv_array_push(&cmd.args, "--pack-loose-unreachable");
|
||||
} else {
|
||||
argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
|
||||
}
|
||||
|
@ -378,7 +388,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
item->string,
|
||||
exts[ext].name);
|
||||
if (remove_path(fname))
|
||||
warning(_("removing '%s' failed"), fname);
|
||||
warning(_("failed to remove '%s'"), fname);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
|
|||
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
struct diff_filespec *one = q->queue[i]->one;
|
||||
int is_missing = !(one->mode && !is_null_sha1(one->sha1));
|
||||
int is_missing = !(one->mode && !is_null_oid(&one->oid));
|
||||
struct cache_entry *ce;
|
||||
|
||||
if (is_missing && !intent_to_add) {
|
||||
|
@ -129,7 +129,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
|
|||
continue;
|
||||
}
|
||||
|
||||
ce = make_cache_entry(one->mode, one->sha1, one->path,
|
||||
ce = make_cache_entry(one->mode, one->oid.hash, one->path,
|
||||
0, 0);
|
||||
if (!ce)
|
||||
die(_("make_cache_entry failed for path '%s'"),
|
||||
|
@ -158,7 +158,7 @@ static int read_from_tree(const struct pathspec *pathspec,
|
|||
return 1;
|
||||
diffcore_std(&opt);
|
||||
diff_flush(&opt);
|
||||
free_pathspec(&opt.pathspec);
|
||||
clear_pathspec(&opt.pathspec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "log-tree.h"
|
||||
#include "graph.h"
|
||||
#include "bisect.h"
|
||||
#include "progress.h"
|
||||
|
||||
static const char rev_list_usage[] =
|
||||
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
|
||||
|
@ -49,12 +50,17 @@ static const char rev_list_usage[] =
|
|||
" --bisect-all"
|
||||
;
|
||||
|
||||
static struct progress *progress;
|
||||
static unsigned progress_counter;
|
||||
|
||||
static void finish_commit(struct commit *commit, void *data);
|
||||
static void show_commit(struct commit *commit, void *data)
|
||||
{
|
||||
struct rev_list_info *info = data;
|
||||
struct rev_info *revs = info->revs;
|
||||
|
||||
display_progress(progress, ++progress_counter);
|
||||
|
||||
if (info->flags & REV_LIST_QUIET) {
|
||||
finish_commit(commit, data);
|
||||
return;
|
||||
|
@ -190,6 +196,7 @@ static void show_object(struct object *obj, const char *name, void *cb_data)
|
|||
{
|
||||
struct rev_list_info *info = cb_data;
|
||||
finish_object(obj, name, cb_data);
|
||||
display_progress(progress, ++progress_counter);
|
||||
if (info->flags & REV_LIST_QUIET)
|
||||
return;
|
||||
show_object_with_name(stdout, obj, name);
|
||||
|
@ -276,6 +283,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
|||
int bisect_show_vars = 0;
|
||||
int bisect_find_all = 0;
|
||||
int use_bitmap_index = 0;
|
||||
const char *show_progress = NULL;
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
init_revisions(&revs, prefix);
|
||||
|
@ -325,6 +333,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
|||
test_bitmap_walk(&revs);
|
||||
return 0;
|
||||
}
|
||||
if (skip_prefix(arg, "--progress=", &arg)) {
|
||||
show_progress = arg;
|
||||
continue;
|
||||
}
|
||||
usage(rev_list_usage);
|
||||
|
||||
}
|
||||
|
@ -355,6 +367,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
|||
if (bisect_list)
|
||||
revs.limited = 1;
|
||||
|
||||
if (show_progress)
|
||||
progress = start_progress_delay(show_progress, 0, 0, 2);
|
||||
|
||||
if (use_bitmap_index && !revs.prune) {
|
||||
if (revs.count && !revs.left_right && !revs.cherry_mark) {
|
||||
uint32_t commit_count;
|
||||
|
@ -392,6 +407,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
|||
|
||||
traverse_commit_list(&revs, show_commit, show_object, &info);
|
||||
|
||||
stop_progress(&progress);
|
||||
|
||||
if (revs.count) {
|
||||
if (revs.left_right && revs.cherry_mark)
|
||||
printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);
|
||||
|
|
|
@ -233,11 +233,11 @@ void shortlog_init(struct shortlog *log)
|
|||
|
||||
int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
static struct shortlog log;
|
||||
static struct rev_info rev;
|
||||
struct shortlog log = { STRING_LIST_INIT_NODUP };
|
||||
struct rev_info rev;
|
||||
int nongit = !startup_info->have_repository;
|
||||
|
||||
static const struct option options[] = {
|
||||
const struct option options[] = {
|
||||
OPT_BOOL('n', "numbered", &log.sort_by_number,
|
||||
N_("sort output according to the number of commits per author")),
|
||||
OPT_BOOL('s', "summary", &log.summary,
|
||||
|
@ -276,6 +276,7 @@ parse_done:
|
|||
|
||||
log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
|
||||
log.abbrev = rev.abbrev;
|
||||
log.file = rev.diffopt.file;
|
||||
|
||||
/* assume HEAD if from a tty */
|
||||
if (!nongit && !rev.pending.nr && isatty(0))
|
||||
|
@ -289,6 +290,8 @@ parse_done:
|
|||
get_from_rev(&rev, &log);
|
||||
|
||||
shortlog_output(&log);
|
||||
if (log.file != stdout)
|
||||
fclose(log.file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -310,22 +313,24 @@ void shortlog_output(struct shortlog *log)
|
|||
for (i = 0; i < log->list.nr; i++) {
|
||||
const struct string_list_item *item = &log->list.items[i];
|
||||
if (log->summary) {
|
||||
printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string);
|
||||
fprintf(log->file, "%6d\t%s\n",
|
||||
(int)UTIL_TO_INT(item), item->string);
|
||||
} else {
|
||||
struct string_list *onelines = item->util;
|
||||
printf("%s (%d):\n", item->string, onelines->nr);
|
||||
fprintf(log->file, "%s (%d):\n",
|
||||
item->string, onelines->nr);
|
||||
for (j = onelines->nr - 1; j >= 0; j--) {
|
||||
const char *msg = onelines->items[j].string;
|
||||
|
||||
if (log->wrap_lines) {
|
||||
strbuf_reset(&sb);
|
||||
add_wrapped_shortlog_msg(&sb, msg, log);
|
||||
fwrite(sb.buf, sb.len, 1, stdout);
|
||||
fwrite(sb.buf, sb.len, 1, log->file);
|
||||
}
|
||||
else
|
||||
printf(" %s\n", msg);
|
||||
fprintf(log->file, " %s\n", msg);
|
||||
}
|
||||
putchar('\n');
|
||||
putc('\n', log->file);
|
||||
onelines->strdup_strings = 1;
|
||||
string_list_clear(onelines, 0);
|
||||
free(onelines);
|
||||
|
|
|
@ -444,8 +444,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
|
|||
static int clone_submodule(const char *path, const char *gitdir, const char *url,
|
||||
const char *depth, const char *reference, int quiet)
|
||||
{
|
||||
struct child_process cp;
|
||||
child_process_init(&cp);
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
|
||||
argv_array_push(&cp.args, "clone");
|
||||
argv_array_push(&cp.args, "--no-checkout");
|
||||
|
@ -579,6 +578,7 @@ struct submodule_update_clone {
|
|||
|
||||
/* configuration parameters which are passed on to the children */
|
||||
int quiet;
|
||||
int recommend_shallow;
|
||||
const char *reference;
|
||||
const char *depth;
|
||||
const char *recursive_prefix;
|
||||
|
@ -589,10 +589,14 @@ struct submodule_update_clone {
|
|||
|
||||
/* If we want to stop as fast as possible and return an error */
|
||||
unsigned quickstop : 1;
|
||||
|
||||
/* failed clones to be retried again */
|
||||
const struct cache_entry **failed_clones;
|
||||
int failed_clones_nr, failed_clones_alloc;
|
||||
};
|
||||
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
|
||||
SUBMODULE_UPDATE_STRATEGY_INIT, 0, NULL, NULL, NULL, NULL, \
|
||||
STRING_LIST_INIT_DUP, 0}
|
||||
SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, NULL, NULL, NULL, NULL, \
|
||||
STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
|
||||
|
||||
|
||||
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
|
||||
|
@ -696,6 +700,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
|||
argv_array_push(&child->args, "--quiet");
|
||||
if (suc->prefix)
|
||||
argv_array_pushl(&child->args, "--prefix", suc->prefix, NULL);
|
||||
if (suc->recommend_shallow && sub->recommend_shallow == 1)
|
||||
argv_array_push(&child->args, "--depth=1");
|
||||
argv_array_pushl(&child->args, "--path", sub->path, NULL);
|
||||
argv_array_pushl(&child->args, "--name", sub->name, NULL);
|
||||
argv_array_pushl(&child->args, "--url", url, NULL);
|
||||
|
@ -715,23 +721,51 @@ cleanup:
|
|||
static int update_clone_get_next_task(struct child_process *child,
|
||||
struct strbuf *err,
|
||||
void *suc_cb,
|
||||
void **void_task_cb)
|
||||
void **idx_task_cb)
|
||||
{
|
||||
struct submodule_update_clone *suc = suc_cb;
|
||||
const struct cache_entry *ce;
|
||||
int index;
|
||||
|
||||
for (; suc->current < suc->list.nr; suc->current++) {
|
||||
const struct cache_entry *ce = suc->list.entries[suc->current];
|
||||
ce = suc->list.entries[suc->current];
|
||||
if (prepare_to_clone_next_submodule(ce, child, suc, err)) {
|
||||
int *p = xmalloc(sizeof(*p));
|
||||
*p = suc->current;
|
||||
*idx_task_cb = p;
|
||||
suc->current++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The loop above tried cloning each submodule once, now try the
|
||||
* stragglers again, which we can imagine as an extension of the
|
||||
* entry list.
|
||||
*/
|
||||
index = suc->current - suc->list.nr;
|
||||
if (index < suc->failed_clones_nr) {
|
||||
int *p;
|
||||
ce = suc->failed_clones[index];
|
||||
if (!prepare_to_clone_next_submodule(ce, child, suc, err)) {
|
||||
suc->current ++;
|
||||
strbuf_addf(err, "BUG: submodule considered for cloning,"
|
||||
"doesn't need cloning any more?\n");
|
||||
return 0;
|
||||
}
|
||||
p = xmalloc(sizeof(*p));
|
||||
*p = suc->current;
|
||||
*idx_task_cb = p;
|
||||
suc->current ++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_clone_start_failure(struct strbuf *err,
|
||||
void *suc_cb,
|
||||
void *void_task_cb)
|
||||
void *idx_task_cb)
|
||||
{
|
||||
struct submodule_update_clone *suc = suc_cb;
|
||||
suc->quickstop = 1;
|
||||
|
@ -741,15 +775,39 @@ static int update_clone_start_failure(struct strbuf *err,
|
|||
static int update_clone_task_finished(int result,
|
||||
struct strbuf *err,
|
||||
void *suc_cb,
|
||||
void *void_task_cb)
|
||||
void *idx_task_cb)
|
||||
{
|
||||
const struct cache_entry *ce;
|
||||
struct submodule_update_clone *suc = suc_cb;
|
||||
|
||||
int *idxP = *(int**)idx_task_cb;
|
||||
int idx = *idxP;
|
||||
free(idxP);
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
suc->quickstop = 1;
|
||||
return 1;
|
||||
if (idx < suc->list.nr) {
|
||||
ce = suc->list.entries[idx];
|
||||
strbuf_addf(err, _("Failed to clone '%s'. Retry scheduled"),
|
||||
ce->name);
|
||||
strbuf_addch(err, '\n');
|
||||
ALLOC_GROW(suc->failed_clones,
|
||||
suc->failed_clones_nr + 1,
|
||||
suc->failed_clones_alloc);
|
||||
suc->failed_clones[suc->failed_clones_nr++] = ce;
|
||||
return 0;
|
||||
} else {
|
||||
idx -= suc->list.nr;
|
||||
ce = suc->failed_clones[idx];
|
||||
strbuf_addf(err, _("Failed to clone '%s' a second time, aborting"),
|
||||
ce->name);
|
||||
strbuf_addch(err, '\n');
|
||||
suc->quickstop = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_clone(int argc, const char **argv, const char *prefix)
|
||||
|
@ -778,6 +836,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
|||
"specified number of revisions")),
|
||||
OPT_INTEGER('j', "jobs", &max_jobs,
|
||||
N_("parallel jobs")),
|
||||
OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
|
||||
N_("whether the initial clone should follow the shallow recommendation")),
|
||||
OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
|
||||
OPT_END()
|
||||
};
|
||||
|
@ -835,13 +895,64 @@ static int resolve_relative_path(int argc, const char **argv, const char *prefix
|
|||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
if (argc != 3)
|
||||
die("submodule--helper relative_path takes exactly 2 arguments, got %d", argc);
|
||||
die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
|
||||
|
||||
printf("%s", relative_path(argv[1], argv[2], &sb));
|
||||
strbuf_release(&sb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *remote_submodule_branch(const char *path)
|
||||
{
|
||||
const struct submodule *sub;
|
||||
gitmodules_config();
|
||||
git_config(submodule_config, NULL);
|
||||
|
||||
sub = submodule_from_path(null_sha1, path);
|
||||
if (!sub)
|
||||
return NULL;
|
||||
|
||||
if (!sub->branch)
|
||||
return "master";
|
||||
|
||||
if (!strcmp(sub->branch, ".")) {
|
||||
unsigned char sha1[20];
|
||||
const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
|
||||
|
||||
if (!refname)
|
||||
die(_("No such ref: %s"), "HEAD");
|
||||
|
||||
/* detached HEAD */
|
||||
if (!strcmp(refname, "HEAD"))
|
||||
die(_("Submodule (%s) branch configured to inherit "
|
||||
"branch from superproject, but the superproject "
|
||||
"is not on any branch"), sub->name);
|
||||
|
||||
if (!skip_prefix(refname, "refs/heads/", &refname))
|
||||
die(_("Expecting a full ref name, got %s"), refname);
|
||||
return refname;
|
||||
}
|
||||
|
||||
return sub->branch;
|
||||
}
|
||||
|
||||
static int resolve_remote_submodule_branch(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
const char *ret;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
if (argc != 2)
|
||||
die("submodule--helper remote-branch takes exactly one arguments, got %d", argc);
|
||||
|
||||
ret = remote_submodule_branch(argv[1]);
|
||||
if (!ret)
|
||||
die("submodule %s doesn't exist", argv[1]);
|
||||
|
||||
printf("%s", ret);
|
||||
strbuf_release(&sb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cmd_struct {
|
||||
const char *cmd;
|
||||
int (*fn)(int, const char **, const char *);
|
||||
|
@ -855,7 +966,8 @@ static struct cmd_struct commands[] = {
|
|||
{"relative-path", resolve_relative_path},
|
||||
{"resolve-relative-url", resolve_relative_url},
|
||||
{"resolve-relative-url-test", resolve_relative_url_test},
|
||||
{"init", module_init}
|
||||
{"init", module_init},
|
||||
{"remote-branch", resolve_remote_submodule_branch}
|
||||
};
|
||||
|
||||
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
|
||||
|
|
|
@ -355,7 +355,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||
return; /* we are done */
|
||||
else {
|
||||
/* cannot resolve yet --- queue it */
|
||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||
hashclr(obj_list[nr].sha1);
|
||||
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
|
||||
return;
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||
* The delta base object is itself a delta that
|
||||
* has not been resolved yet.
|
||||
*/
|
||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||
hashclr(obj_list[nr].sha1);
|
||||
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -759,7 +759,7 @@ static int do_reupdate(int ac, const char **av,
|
|||
if (save_nr != active_nr)
|
||||
goto redo;
|
||||
}
|
||||
free_pathspec(&pathspec);
|
||||
clear_pathspec(&pathspec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1146,7 +1146,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
|
|||
report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
|
||||
break;
|
||||
default:
|
||||
die("Bug: bad untracked_cache value: %d", untracked_cache);
|
||||
die("BUG: bad untracked_cache value: %d", untracked_cache);
|
||||
}
|
||||
|
||||
if (active_cache_changed) {
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
|
||||
static const char * const worktree_usage[] = {
|
||||
N_("git worktree add [<options>] <path> [<branch>]"),
|
||||
N_("git worktree prune [<options>]"),
|
||||
N_("git worktree list [<options>]"),
|
||||
N_("git worktree lock [<options>] <path>"),
|
||||
N_("git worktree prune [<options>]"),
|
||||
N_("git worktree unlock <path>"),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -95,7 +97,7 @@ static void prune_worktrees(void)
|
|||
if (!dir)
|
||||
return;
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||
if (is_dot_or_dotdot(d->d_name))
|
||||
continue;
|
||||
strbuf_reset(&reason);
|
||||
if (!prune_worktree(d->d_name, &reason))
|
||||
|
@ -192,7 +194,7 @@ static int add_worktree(const char *path, const char *refname,
|
|||
struct strbuf sb = STRBUF_INIT;
|
||||
const char *name;
|
||||
struct stat st;
|
||||
struct child_process cp;
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
struct argv_array child_env = ARGV_ARRAY_INIT;
|
||||
int counter = 0, len, ret;
|
||||
struct strbuf symref = STRBUF_INIT;
|
||||
|
@ -262,7 +264,7 @@ static int add_worktree(const char *path, const char *refname,
|
|||
*/
|
||||
strbuf_reset(&sb);
|
||||
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
|
||||
write_file(sb.buf, "0000000000000000000000000000000000000000");
|
||||
write_file(sb.buf, "%s", sha1_to_hex(null_sha1));
|
||||
strbuf_reset(&sb);
|
||||
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
|
||||
write_file(sb.buf, "../..");
|
||||
|
@ -271,7 +273,6 @@ static int add_worktree(const char *path, const char *refname,
|
|||
|
||||
argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
|
||||
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.git_cmd = 1;
|
||||
|
||||
if (commit)
|
||||
|
@ -337,9 +338,12 @@ static int add(int ac, const char **av, const char *prefix)
|
|||
if (ac < 1 || ac > 2)
|
||||
usage_with_options(worktree_usage, options);
|
||||
|
||||
path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
|
||||
path = prefix_filename(prefix, strlen(prefix), av[0]);
|
||||
branch = ac < 2 ? "HEAD" : av[1];
|
||||
|
||||
if (!strcmp(branch, "-"))
|
||||
branch = "@{-1}";
|
||||
|
||||
opts.force_new_branch = !!new_branch_force;
|
||||
if (opts.force_new_branch) {
|
||||
struct strbuf symref = STRBUF_INIT;
|
||||
|
@ -360,8 +364,7 @@ static int add(int ac, const char **av, const char *prefix)
|
|||
}
|
||||
|
||||
if (opts.new_branch) {
|
||||
struct child_process cp;
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
cp.git_cmd = 1;
|
||||
argv_array_push(&cp.args, "branch");
|
||||
if (opts.force_new_branch)
|
||||
|
@ -459,6 +462,66 @@ static int list(int ac, const char **av, const char *prefix)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lock_worktree(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
const char *reason = "", *old_reason;
|
||||
struct option options[] = {
|
||||
OPT_STRING(0, "reason", &reason, N_("string"),
|
||||
N_("reason for locking")),
|
||||
OPT_END()
|
||||
};
|
||||
struct worktree **worktrees, *wt;
|
||||
|
||||
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
|
||||
if (ac != 1)
|
||||
usage_with_options(worktree_usage, options);
|
||||
|
||||
worktrees = get_worktrees();
|
||||
wt = find_worktree(worktrees, prefix, av[0]);
|
||||
if (!wt)
|
||||
die(_("'%s' is not a working tree"), av[0]);
|
||||
if (is_main_worktree(wt))
|
||||
die(_("The main working tree cannot be locked or unlocked"));
|
||||
|
||||
old_reason = is_worktree_locked(wt);
|
||||
if (old_reason) {
|
||||
if (*old_reason)
|
||||
die(_("'%s' is already locked, reason: %s"),
|
||||
av[0], old_reason);
|
||||
die(_("'%s' is already locked"), av[0]);
|
||||
}
|
||||
|
||||
write_file(git_common_path("worktrees/%s/locked", wt->id),
|
||||
"%s", reason);
|
||||
free_worktrees(worktrees);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unlock_worktree(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
OPT_END()
|
||||
};
|
||||
struct worktree **worktrees, *wt;
|
||||
int ret;
|
||||
|
||||
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
|
||||
if (ac != 1)
|
||||
usage_with_options(worktree_usage, options);
|
||||
|
||||
worktrees = get_worktrees();
|
||||
wt = find_worktree(worktrees, prefix, av[0]);
|
||||
if (!wt)
|
||||
die(_("'%s' is not a working tree"), av[0]);
|
||||
if (is_main_worktree(wt))
|
||||
die(_("The main working tree cannot be locked or unlocked"));
|
||||
if (!is_worktree_locked(wt))
|
||||
die(_("'%s' is not locked"), av[0]);
|
||||
ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id));
|
||||
free_worktrees(worktrees);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_worktree(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
|
@ -467,11 +530,17 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
|
|||
|
||||
if (ac < 2)
|
||||
usage_with_options(worktree_usage, options);
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
if (!strcmp(av[1], "add"))
|
||||
return add(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "prune"))
|
||||
return prune(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "list"))
|
||||
return list(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "lock"))
|
||||
return lock_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "unlock"))
|
||||
return unlock_worktree(ac - 1, av + 1, prefix);
|
||||
usage_with_options(worktree_usage, options);
|
||||
}
|
||||
|
|
54
cache.h
54
cache.h
|
@ -1004,6 +1004,11 @@ int adjust_shared_perm(const char *path);
|
|||
* directory while we were working. To be robust against this kind of
|
||||
* race, callers might want to try invoking the function again when it
|
||||
* returns SCLD_VANISHED.
|
||||
*
|
||||
* safe_create_leading_directories() temporarily changes path while it
|
||||
* is working but restores it before returning.
|
||||
* safe_create_leading_directories_const() doesn't modify path, even
|
||||
* temporarily.
|
||||
*/
|
||||
enum scld_error {
|
||||
SCLD_OK = 0,
|
||||
|
@ -1194,6 +1199,7 @@ extern int get_oid_hex(const char *hex, struct object_id *sha1);
|
|||
* printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
|
||||
*/
|
||||
extern char *sha1_to_hex_r(char *out, const unsigned char *sha1);
|
||||
extern char *oid_to_hex_r(char *out, const struct object_id *oid);
|
||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
|
||||
|
||||
|
@ -1373,6 +1379,13 @@ extern struct packed_git {
|
|||
char pack_name[FLEX_ARRAY]; /* more */
|
||||
} *packed_git;
|
||||
|
||||
/*
|
||||
* A most-recently-used ordered version of the packed_git list, which can
|
||||
* be iterated instead of packed_git (and marked via mru_mark).
|
||||
*/
|
||||
struct mru;
|
||||
extern struct mru *packed_git_mru;
|
||||
|
||||
struct pack_entry {
|
||||
off_t offset;
|
||||
unsigned char sha1[20];
|
||||
|
@ -1412,7 +1425,6 @@ extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t
|
|||
extern void close_pack_windows(struct packed_git *);
|
||||
extern void close_all_packs(void);
|
||||
extern void unuse_pack(struct pack_window **);
|
||||
extern void free_pack_by_name(const char *);
|
||||
extern void clear_delta_base_cache(void);
|
||||
extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
|
||||
|
||||
|
@ -1562,10 +1574,18 @@ struct git_config_source {
|
|||
const char *blob;
|
||||
};
|
||||
|
||||
enum config_origin_type {
|
||||
CONFIG_ORIGIN_BLOB,
|
||||
CONFIG_ORIGIN_FILE,
|
||||
CONFIG_ORIGIN_STDIN,
|
||||
CONFIG_ORIGIN_SUBMODULE_BLOB,
|
||||
CONFIG_ORIGIN_CMDLINE
|
||||
};
|
||||
|
||||
typedef int (*config_fn_t)(const char *, const char *, void *);
|
||||
extern int git_default_config(const char *, const char *, void *);
|
||||
extern int git_config_from_file(config_fn_t fn, const char *, void *);
|
||||
extern int git_config_from_mem(config_fn_t fn, const char *origin_type,
|
||||
extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
|
||||
const char *name, const char *buf, size_t len, void *data);
|
||||
extern void git_config_push_parameter(const char *text);
|
||||
extern int git_config_from_parameters(config_fn_t fn, void *data);
|
||||
|
@ -1607,6 +1627,16 @@ extern const char *get_log_output_encoding(void);
|
|||
extern const char *get_commit_output_encoding(void);
|
||||
|
||||
extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
|
||||
|
||||
enum config_scope {
|
||||
CONFIG_SCOPE_UNKNOWN = 0,
|
||||
CONFIG_SCOPE_SYSTEM,
|
||||
CONFIG_SCOPE_GLOBAL,
|
||||
CONFIG_SCOPE_REPO,
|
||||
CONFIG_SCOPE_CMDLINE,
|
||||
};
|
||||
|
||||
extern enum config_scope current_config_scope(void);
|
||||
extern const char *current_config_origin_type(void);
|
||||
extern const char *current_config_name(void);
|
||||
|
||||
|
@ -1699,6 +1729,8 @@ extern int ignore_untracked_cache_config;
|
|||
struct key_value_info {
|
||||
const char *filename;
|
||||
int linenr;
|
||||
enum config_origin_type origin_type;
|
||||
enum config_scope scope;
|
||||
};
|
||||
|
||||
extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
@ -1724,7 +1756,6 @@ extern int copy_file(const char *dst, const char *src, int mode);
|
|||
extern int copy_file_with_time(const char *dst, const char *src, int mode);
|
||||
|
||||
extern void write_or_die(int fd, const void *buf, size_t count);
|
||||
extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
|
||||
extern void fsync_or_die(int fd, const char *);
|
||||
|
||||
extern ssize_t read_in_full(int fd, void *buf, size_t count);
|
||||
|
@ -1736,8 +1767,21 @@ static inline ssize_t write_str_in_full(int fd, const char *str)
|
|||
return write_in_full(fd, str, strlen(str));
|
||||
}
|
||||
|
||||
extern int write_file(const char *path, const char *fmt, ...);
|
||||
extern int write_file_gently(const char *path, const char *fmt, ...);
|
||||
/**
|
||||
* Open (and truncate) the file at path, write the contents of buf to it,
|
||||
* and close it. Dies if any errors are encountered.
|
||||
*/
|
||||
extern void write_file_buf(const char *path, const char *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Like write_file_buf(), but format the contents into a buffer first.
|
||||
* Additionally, write_file() will append a newline if one is not already
|
||||
* present, making it convenient to write text files:
|
||||
*
|
||||
* write_file(path, "counter: %d", ctr);
|
||||
*/
|
||||
__attribute__((format (printf, 2, 3)))
|
||||
extern void write_file(const char *path, const char *fmt, ...);
|
||||
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
|
|
35
color.c
35
color.c
|
@ -123,19 +123,34 @@ static int parse_color(struct color *out, const char *name, int len)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int parse_attr(const char *name, int len)
|
||||
static int parse_attr(const char *name, size_t len)
|
||||
{
|
||||
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",
|
||||
"nobold", "nodim", "noul", "noblink", "noreverse"
|
||||
static const struct {
|
||||
const char *name;
|
||||
size_t len;
|
||||
int val, neg;
|
||||
} attrs[] = {
|
||||
#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
|
||||
ATTR("bold", 1, 22),
|
||||
ATTR("dim", 2, 22),
|
||||
ATTR("italic", 3, 23),
|
||||
ATTR("ul", 4, 24),
|
||||
ATTR("blink", 5, 25),
|
||||
ATTR("reverse", 7, 27),
|
||||
ATTR("strike", 9, 29)
|
||||
#undef ATTR
|
||||
};
|
||||
int negate = 0;
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
|
||||
const char *str = attr_names[i];
|
||||
if (!strncasecmp(name, str, len) && !str[len])
|
||||
return attr_values[i];
|
||||
|
||||
if (skip_prefix_mem(name, len, "no", &name, &len)) {
|
||||
skip_prefix_mem(name, len, "-", &name, &len);
|
||||
negate = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(attrs); i++) {
|
||||
if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
|
||||
return negate ? attrs[i].neg : attrs[i].val;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
15
color.h
15
color.h
|
@ -3,20 +3,23 @@
|
|||
|
||||
struct strbuf;
|
||||
|
||||
/* 2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */
|
||||
/* "\033[1;2;4;5;7;38;5;2xx;48;5;2xxm\0" */
|
||||
/*
|
||||
* The maximum length of ANSI color sequence we would generate:
|
||||
* - leading ESC '[' 2
|
||||
* - attr + ';' 3 * 10 (e.g. "1;")
|
||||
* - attr + ';' 2 * num_attr (e.g. "1;")
|
||||
* - no-attr + ';' 3 * num_attr (e.g. "22;")
|
||||
* - 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.
|
||||
* The above overcounts by one semicolon but it is close enough.
|
||||
*
|
||||
* The space for attributes is also slightly overallocated, as
|
||||
* the negation for some attributes is the same (e.g., nobold and nodim).
|
||||
*
|
||||
* We allocate space for 7 attributes.
|
||||
*/
|
||||
#define COLOR_MAXLEN 70
|
||||
#define COLOR_MAXLEN 75
|
||||
|
||||
#define GIT_COLOR_NORMAL ""
|
||||
#define GIT_COLOR_RESET "\033[m"
|
||||
|
|
|
@ -44,9 +44,9 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
|
|||
memset(p->parent, 0,
|
||||
sizeof(p->parent[0]) * num_parent);
|
||||
|
||||
hashcpy(p->oid.hash, q->queue[i]->two->sha1);
|
||||
oidcpy(&p->oid, &q->queue[i]->two->oid);
|
||||
p->mode = q->queue[i]->two->mode;
|
||||
hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1);
|
||||
oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
|
||||
p->parent[n].mode = q->queue[i]->one->mode;
|
||||
p->parent[n].status = q->queue[i]->status;
|
||||
*tail = p;
|
||||
|
@ -77,7 +77,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
|
|||
continue;
|
||||
}
|
||||
|
||||
hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1);
|
||||
oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
|
||||
p->parent[n].mode = q->queue[i]->one->mode;
|
||||
p->parent[n].status = q->queue[i]->status;
|
||||
|
||||
|
@ -1268,16 +1268,16 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p,
|
|||
for (i = 0; i < num_parent; i++) {
|
||||
pair->one[i].path = p->path;
|
||||
pair->one[i].mode = p->parent[i].mode;
|
||||
hashcpy(pair->one[i].sha1, p->parent[i].oid.hash);
|
||||
pair->one[i].sha1_valid = !is_null_oid(&p->parent[i].oid);
|
||||
oidcpy(&pair->one[i].oid, &p->parent[i].oid);
|
||||
pair->one[i].oid_valid = !is_null_oid(&p->parent[i].oid);
|
||||
pair->one[i].has_more_entries = 1;
|
||||
}
|
||||
pair->one[num_parent - 1].has_more_entries = 0;
|
||||
|
||||
pair->two->path = p->path;
|
||||
pair->two->mode = p->mode;
|
||||
hashcpy(pair->two->sha1, p->oid.hash);
|
||||
pair->two->sha1_valid = !is_null_oid(&p->oid);
|
||||
oidcpy(&pair->two->oid, &p->oid);
|
||||
pair->two->oid_valid = !is_null_oid(&p->oid);
|
||||
return pair;
|
||||
}
|
||||
|
||||
|
@ -1525,7 +1525,7 @@ void diff_tree_combined(const unsigned char *sha1,
|
|||
free(tmp);
|
||||
}
|
||||
|
||||
free_pathspec(&diffopts.pathspec);
|
||||
clear_pathspec(&diffopts.pathspec);
|
||||
}
|
||||
|
||||
void diff_tree_combined_merge(const struct commit *commit, int dense,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* After including this header file, using:
|
||||
*
|
||||
* define_commit_slab(indegee, int);
|
||||
* define_commit_slab(indegree, int);
|
||||
*
|
||||
* will let you call the following functions:
|
||||
*
|
||||
|
@ -126,16 +126,16 @@ static MAYBE_UNUSED elemtype *slabname## _peek(struct slabname *s, \
|
|||
return slabname##_at_peek(s, c, 0); \
|
||||
} \
|
||||
\
|
||||
static int stat_ ##slabname## realloc
|
||||
struct slabname
|
||||
|
||||
/*
|
||||
* Note that this seemingly redundant second declaration is required
|
||||
* Note that this redundant forward declaration is required
|
||||
* to allow a terminating semicolon, which makes instantiations look
|
||||
* like function declarations. I.e., the expansion of
|
||||
*
|
||||
* define_commit_slab(indegree, int);
|
||||
*
|
||||
* ends in 'static int stat_indegreerealloc;'. This would otherwise
|
||||
* ends in 'struct indegree;'. This would otherwise
|
||||
* be a syntax error according (at least) to ISO C. It's hard to
|
||||
* catch because GCC silently parses it by default.
|
||||
*/
|
||||
|
|
10
commit.c
10
commit.c
|
@ -1626,16 +1626,6 @@ struct commit_list **commit_list_append(struct commit *commit,
|
|||
return &new->next;
|
||||
}
|
||||
|
||||
void print_commit_list(struct commit_list *list,
|
||||
const char *format_cur,
|
||||
const char *format_last)
|
||||
{
|
||||
for ( ; list; list = list->next) {
|
||||
const char *format = list->next ? format_cur : format_last;
|
||||
printf(format, oid_to_hex(&list->item->object.oid));
|
||||
}
|
||||
}
|
||||
|
||||
const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
|
||||
{
|
||||
int key_len = strlen(key);
|
||||
|
|
10
commit.h
10
commit.h
|
@ -131,11 +131,17 @@ enum cmit_fmt {
|
|||
CMIT_FMT_FULLER,
|
||||
CMIT_FMT_ONELINE,
|
||||
CMIT_FMT_EMAIL,
|
||||
CMIT_FMT_MBOXRD,
|
||||
CMIT_FMT_USERFORMAT,
|
||||
|
||||
CMIT_FMT_UNSPECIFIED
|
||||
};
|
||||
|
||||
static inline int cmit_fmt_is_mail(enum cmit_fmt fmt)
|
||||
{
|
||||
return (fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_MBOXRD);
|
||||
}
|
||||
|
||||
struct pretty_print_context {
|
||||
/*
|
||||
* Callers should tweak these to change the behavior of pp_* functions.
|
||||
|
@ -373,10 +379,6 @@ extern int parse_signed_commit(const struct commit *commit,
|
|||
struct strbuf *message, struct strbuf *signature);
|
||||
extern int remove_signature(struct strbuf *buf);
|
||||
|
||||
extern void print_commit_list(struct commit_list *list,
|
||||
const char *format_cur,
|
||||
const char *format_last);
|
||||
|
||||
/*
|
||||
* Check the signature of the given commit. The result of the check is stored
|
||||
* in sig->check_result, 'G' for a good signature, 'U' for a good signature
|
||||
|
|
231
config.c
231
config.c
|
@ -24,7 +24,7 @@ struct config_source {
|
|||
size_t pos;
|
||||
} buf;
|
||||
} u;
|
||||
const char *origin_type;
|
||||
enum config_origin_type origin_type;
|
||||
const char *name;
|
||||
const char *path;
|
||||
int die_on_error;
|
||||
|
@ -38,7 +38,33 @@ struct config_source {
|
|||
long (*do_ftell)(struct config_source *c);
|
||||
};
|
||||
|
||||
/*
|
||||
* These variables record the "current" config source, which
|
||||
* can be accessed by parsing callbacks.
|
||||
*
|
||||
* The "cf" variable will be non-NULL only when we are actually parsing a real
|
||||
* config source (file, blob, cmdline, etc).
|
||||
*
|
||||
* The "current_config_kvi" variable will be non-NULL only when we are feeding
|
||||
* cached config from a configset into a callback.
|
||||
*
|
||||
* They should generally never be non-NULL at the same time. If they are both
|
||||
* NULL, then we aren't parsing anything (and depending on the function looking
|
||||
* at the variables, it's either a bug for it to be called in the first place,
|
||||
* or it's a function which can be reused for non-config purposes, and should
|
||||
* fall back to some sane behavior).
|
||||
*/
|
||||
static struct config_source *cf;
|
||||
static struct key_value_info *current_config_kvi;
|
||||
|
||||
/*
|
||||
* Similar to the variables above, this gives access to the "scope" of the
|
||||
* current value (repo, global, etc). For cached values, it can be found via
|
||||
* the current_config_kvi as above. During parsing, the current value can be
|
||||
* found in this variable. It's not part of "cf" because it transcends a single
|
||||
* file (i.e., a file included from .git/config is still in "repo" scope).
|
||||
*/
|
||||
static enum config_scope current_parsing_scope;
|
||||
|
||||
static int zlib_compression_seen;
|
||||
|
||||
|
@ -131,7 +157,9 @@ static int handle_path_include(const char *path, struct config_include_data *inc
|
|||
if (!access_or_die(path, R_OK, 0)) {
|
||||
if (++inc->depth > MAX_INCLUDE_DEPTH)
|
||||
die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
|
||||
cf && cf->name ? cf->name : "the command line");
|
||||
!cf ? "<unknown>" :
|
||||
cf->name ? cf->name :
|
||||
"the command line");
|
||||
ret = git_config_from_file(git_config_include, path, inc);
|
||||
inc->depth--;
|
||||
}
|
||||
|
@ -205,32 +233,41 @@ int git_config_parse_parameter(const char *text,
|
|||
int git_config_from_parameters(config_fn_t fn, void *data)
|
||||
{
|
||||
const char *env = getenv(CONFIG_DATA_ENVIRONMENT);
|
||||
int ret = 0;
|
||||
char *envw;
|
||||
const char **argv = NULL;
|
||||
int nr = 0, alloc = 0;
|
||||
int i;
|
||||
struct config_source source;
|
||||
|
||||
if (!env)
|
||||
return 0;
|
||||
|
||||
memset(&source, 0, sizeof(source));
|
||||
source.prev = cf;
|
||||
source.origin_type = CONFIG_ORIGIN_CMDLINE;
|
||||
cf = &source;
|
||||
|
||||
/* sq_dequote will write over it */
|
||||
envw = xstrdup(env);
|
||||
|
||||
if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
|
||||
free(envw);
|
||||
return error("bogus format in " CONFIG_DATA_ENVIRONMENT);
|
||||
ret = error("bogus format in " CONFIG_DATA_ENVIRONMENT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (git_config_parse_parameter(argv[i], fn, data) < 0) {
|
||||
free(argv);
|
||||
free(envw);
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
free(argv);
|
||||
free(envw);
|
||||
return nr > 0;
|
||||
cf = source.prev;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_next_char(void)
|
||||
|
@ -417,6 +454,8 @@ static int git_parse_source(config_fn_t fn, void *data)
|
|||
int comment = 0;
|
||||
int baselen = 0;
|
||||
struct strbuf *var = &cf->var;
|
||||
int error_return = 0;
|
||||
char *error_msg = NULL;
|
||||
|
||||
/* U+FEFF Byte Order Mark in UTF8 */
|
||||
const char *bomptr = utf8_bom;
|
||||
|
@ -471,10 +510,40 @@ static int git_parse_source(config_fn_t fn, void *data)
|
|||
if (get_value(fn, data, var) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cf->origin_type) {
|
||||
case CONFIG_ORIGIN_BLOB:
|
||||
error_msg = xstrfmt(_("bad config line %d in blob %s"),
|
||||
cf->linenr, cf->name);
|
||||
break;
|
||||
case CONFIG_ORIGIN_FILE:
|
||||
error_msg = xstrfmt(_("bad config line %d in file %s"),
|
||||
cf->linenr, cf->name);
|
||||
break;
|
||||
case CONFIG_ORIGIN_STDIN:
|
||||
error_msg = xstrfmt(_("bad config line %d in standard input"),
|
||||
cf->linenr);
|
||||
break;
|
||||
case CONFIG_ORIGIN_SUBMODULE_BLOB:
|
||||
error_msg = xstrfmt(_("bad config line %d in submodule-blob %s"),
|
||||
cf->linenr, cf->name);
|
||||
break;
|
||||
case CONFIG_ORIGIN_CMDLINE:
|
||||
error_msg = xstrfmt(_("bad config line %d in command line %s"),
|
||||
cf->linenr, cf->name);
|
||||
break;
|
||||
default:
|
||||
error_msg = xstrfmt(_("bad config line %d in %s"),
|
||||
cf->linenr, cf->name);
|
||||
}
|
||||
|
||||
if (cf->die_on_error)
|
||||
die(_("bad config line %d in %s %s"), cf->linenr, cf->origin_type, cf->name);
|
||||
die("%s", error_msg);
|
||||
else
|
||||
return error(_("bad config line %d in %s %s"), cf->linenr, cf->origin_type, cf->name);
|
||||
error_return = error("%s", error_msg);
|
||||
|
||||
free(error_msg);
|
||||
return error_return;
|
||||
}
|
||||
|
||||
static int parse_unit_factor(const char *end, uintmax_t *val)
|
||||
|
@ -583,16 +652,35 @@ int git_parse_ulong(const char *value, unsigned long *ret)
|
|||
NORETURN
|
||||
static void die_bad_number(const char *name, const char *value)
|
||||
{
|
||||
const char *reason = errno == ERANGE ?
|
||||
"out of range" :
|
||||
"invalid unit";
|
||||
const char * error_type = (errno == ERANGE)? _("out of range"):_("invalid unit");
|
||||
|
||||
if (!value)
|
||||
value = "";
|
||||
|
||||
if (cf && cf->origin_type && cf->name)
|
||||
die(_("bad numeric config value '%s' for '%s' in %s %s: %s"),
|
||||
value, name, cf->origin_type, cf->name, reason);
|
||||
die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason);
|
||||
if (!(cf && cf->name))
|
||||
die(_("bad numeric config value '%s' for '%s': %s"),
|
||||
value, name, error_type);
|
||||
|
||||
switch (cf->origin_type) {
|
||||
case CONFIG_ORIGIN_BLOB:
|
||||
die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
|
||||
value, name, cf->name, error_type);
|
||||
case CONFIG_ORIGIN_FILE:
|
||||
die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
|
||||
value, name, cf->name, error_type);
|
||||
case CONFIG_ORIGIN_STDIN:
|
||||
die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
|
||||
value, name, error_type);
|
||||
case CONFIG_ORIGIN_SUBMODULE_BLOB:
|
||||
die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
|
||||
value, name, cf->name, error_type);
|
||||
case CONFIG_ORIGIN_CMDLINE:
|
||||
die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
|
||||
value, name, cf->name, error_type);
|
||||
default:
|
||||
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
|
||||
value, name, cf->name, error_type);
|
||||
}
|
||||
}
|
||||
|
||||
int git_config_int(const char *name, const char *value)
|
||||
|
@ -1069,7 +1157,8 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
|
|||
}
|
||||
|
||||
static int do_config_from_file(config_fn_t fn,
|
||||
const char *origin_type, const char *name, const char *path, FILE *f,
|
||||
const enum config_origin_type origin_type,
|
||||
const char *name, const char *path, FILE *f,
|
||||
void *data)
|
||||
{
|
||||
struct config_source top;
|
||||
|
@ -1088,7 +1177,7 @@ static int do_config_from_file(config_fn_t fn,
|
|||
|
||||
static int git_config_from_stdin(config_fn_t fn, void *data)
|
||||
{
|
||||
return do_config_from_file(fn, "standard input", "", NULL, stdin, data);
|
||||
return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin, data);
|
||||
}
|
||||
|
||||
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
|
||||
|
@ -1099,14 +1188,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
|
|||
f = fopen(filename, "r");
|
||||
if (f) {
|
||||
flockfile(f);
|
||||
ret = do_config_from_file(fn, "file", filename, filename, f, data);
|
||||
ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data);
|
||||
funlockfile(f);
|
||||
fclose(f);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_from_mem(config_fn_t fn, const char *origin_type,
|
||||
int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type,
|
||||
const char *name, const char *buf, size_t len, void *data)
|
||||
{
|
||||
struct config_source top;
|
||||
|
@ -1143,7 +1232,7 @@ static int git_config_from_blob_sha1(config_fn_t fn,
|
|||
return error("reference '%s' does not point to a blob", name);
|
||||
}
|
||||
|
||||
ret = git_config_from_mem(fn, "blob", name, buf, size, data);
|
||||
ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data);
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
|
@ -1197,47 +1286,36 @@ int git_config_system(void)
|
|||
|
||||
static int do_git_config_sequence(config_fn_t fn, void *data)
|
||||
{
|
||||
int ret = 0, found = 0;
|
||||
int ret = 0;
|
||||
char *xdg_config = xdg_config_home("config");
|
||||
char *user_config = expand_user_path("~/.gitconfig");
|
||||
char *repo_config = git_pathdup("config");
|
||||
|
||||
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
|
||||
current_parsing_scope = CONFIG_SCOPE_SYSTEM;
|
||||
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0))
|
||||
ret += git_config_from_file(fn, git_etc_gitconfig(),
|
||||
data);
|
||||
found += 1;
|
||||
}
|
||||
|
||||
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK)) {
|
||||
current_parsing_scope = CONFIG_SCOPE_GLOBAL;
|
||||
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
|
||||
ret += git_config_from_file(fn, xdg_config, data);
|
||||
found += 1;
|
||||
}
|
||||
|
||||
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK)) {
|
||||
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
|
||||
ret += git_config_from_file(fn, user_config, data);
|
||||
found += 1;
|
||||
}
|
||||
|
||||
if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
|
||||
current_parsing_scope = CONFIG_SCOPE_REPO;
|
||||
if (repo_config && !access_or_die(repo_config, R_OK, 0))
|
||||
ret += git_config_from_file(fn, repo_config, data);
|
||||
found += 1;
|
||||
}
|
||||
|
||||
switch (git_config_from_parameters(fn, data)) {
|
||||
case -1: /* error */
|
||||
current_parsing_scope = CONFIG_SCOPE_CMDLINE;
|
||||
if (git_config_from_parameters(fn, data) < 0)
|
||||
die(_("unable to parse command-line config"));
|
||||
break;
|
||||
case 0: /* found nothing */
|
||||
break;
|
||||
default: /* found at least one item */
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
|
||||
current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
|
||||
free(xdg_config);
|
||||
free(user_config);
|
||||
free(repo_config);
|
||||
return ret == 0 ? found : ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_with_options(config_fn_t fn, void *data,
|
||||
|
@ -1272,7 +1350,7 @@ static void git_config_raw(config_fn_t fn, void *data)
|
|||
if (git_config_with_options(fn, data, NULL, 1) < 0)
|
||||
/*
|
||||
* git_config_with_options() normally returns only
|
||||
* positive values, as most errors are fatal, and
|
||||
* zero, as most errors are fatal, and
|
||||
* non-fatal potential errors are guarded by "if"
|
||||
* statements that are entered only when no error is
|
||||
* possible.
|
||||
|
@ -1290,16 +1368,20 @@ static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
|
|||
struct string_list *values;
|
||||
struct config_set_element *entry;
|
||||
struct configset_list *list = &cs->list;
|
||||
struct key_value_info *kv_info;
|
||||
|
||||
for (i = 0; i < list->nr; i++) {
|
||||
entry = list->items[i].e;
|
||||
value_index = list->items[i].value_index;
|
||||
values = &entry->value_list;
|
||||
if (fn(entry->key, values->items[value_index].string, data) < 0) {
|
||||
kv_info = values->items[value_index].util;
|
||||
git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
|
||||
}
|
||||
|
||||
current_config_kvi = values->items[value_index].util;
|
||||
|
||||
if (fn(entry->key, values->items[value_index].string, data) < 0)
|
||||
git_die_config_linenr(entry->key,
|
||||
current_config_kvi->filename,
|
||||
current_config_kvi->linenr);
|
||||
|
||||
current_config_kvi = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1356,14 +1438,19 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
|
|||
l_item->e = e;
|
||||
l_item->value_index = e->value_list.nr - 1;
|
||||
|
||||
if (cf) {
|
||||
if (!cf)
|
||||
die("BUG: configset_add_value has no source");
|
||||
if (cf->name) {
|
||||
kv_info->filename = strintern(cf->name);
|
||||
kv_info->linenr = cf->linenr;
|
||||
kv_info->origin_type = cf->origin_type;
|
||||
} else {
|
||||
/* for values read from `git_config_from_parameters()` */
|
||||
kv_info->filename = NULL;
|
||||
kv_info->linenr = -1;
|
||||
kv_info->origin_type = CONFIG_ORIGIN_CMDLINE;
|
||||
}
|
||||
kv_info->scope = current_parsing_scope;
|
||||
si->util = kv_info;
|
||||
|
||||
return 0;
|
||||
|
@ -2442,10 +2529,46 @@ int parse_config_key(const char *var,
|
|||
|
||||
const char *current_config_origin_type(void)
|
||||
{
|
||||
return cf && cf->origin_type ? cf->origin_type : "command line";
|
||||
int type;
|
||||
if (current_config_kvi)
|
||||
type = current_config_kvi->origin_type;
|
||||
else if(cf)
|
||||
type = cf->origin_type;
|
||||
else
|
||||
die("BUG: current_config_origin_type called outside config callback");
|
||||
|
||||
switch (type) {
|
||||
case CONFIG_ORIGIN_BLOB:
|
||||
return "blob";
|
||||
case CONFIG_ORIGIN_FILE:
|
||||
return "file";
|
||||
case CONFIG_ORIGIN_STDIN:
|
||||
return "standard input";
|
||||
case CONFIG_ORIGIN_SUBMODULE_BLOB:
|
||||
return "submodule-blob";
|
||||
case CONFIG_ORIGIN_CMDLINE:
|
||||
return "command line";
|
||||
default:
|
||||
die("BUG: unknown config origin type");
|
||||
}
|
||||
}
|
||||
|
||||
const char *current_config_name(void)
|
||||
{
|
||||
return cf && cf->name ? cf->name : "";
|
||||
const char *name;
|
||||
if (current_config_kvi)
|
||||
name = current_config_kvi->filename;
|
||||
else if (cf)
|
||||
name = cf->name;
|
||||
else
|
||||
die("BUG: current_config_name called outside config callback");
|
||||
return name ? name : "";
|
||||
}
|
||||
|
||||
enum config_scope current_config_scope(void)
|
||||
{
|
||||
if (current_config_kvi)
|
||||
return current_config_kvi->scope;
|
||||
else
|
||||
return current_parsing_scope;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ ifeq ($(uname_S),Linux)
|
|||
HAVE_DEV_TTY = YesPlease
|
||||
HAVE_CLOCK_GETTIME = YesPlease
|
||||
HAVE_CLOCK_MONOTONIC = YesPlease
|
||||
# -lrt is needed for clock_gettime on glibc <= 2.16
|
||||
NEEDS_LIBRT = YesPlease
|
||||
HAVE_GETDELIM = YesPlease
|
||||
SANE_TEXT_GREP=-a
|
||||
endif
|
||||
|
@ -207,6 +209,7 @@ ifeq ($(uname_S),FreeBSD)
|
|||
HAVE_PATHS_H = YesPlease
|
||||
GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes
|
||||
HAVE_BSD_SYSCTL = YesPlease
|
||||
PAGER_ENV = LESS=FRX LV=-c MORE=FRX
|
||||
endif
|
||||
ifeq ($(uname_S),OpenBSD)
|
||||
NO_STRCASESTR = YesPlease
|
||||
|
|
15
connect.c
15
connect.c
|
@ -658,6 +658,19 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
|
|||
|
||||
static struct child_process no_fork = CHILD_PROCESS_INIT;
|
||||
|
||||
static const char *get_ssh_command(void)
|
||||
{
|
||||
const char *ssh;
|
||||
|
||||
if ((ssh = getenv("GIT_SSH_COMMAND")))
|
||||
return ssh;
|
||||
|
||||
if (!git_config_get_string_const("core.sshcommand", &ssh))
|
||||
return ssh;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns a dummy child_process if the transport protocol does not
|
||||
* need fork(2), or a struct child_process object if it does. Once done,
|
||||
|
@ -758,7 +771,7 @@ struct child_process *git_connect(int fd[2], const char *url,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ssh = getenv("GIT_SSH_COMMAND");
|
||||
ssh = get_ssh_command();
|
||||
if (!ssh) {
|
||||
const char *base;
|
||||
char *ssh_dup;
|
||||
|
|
71
connected.c
71
connected.c
|
@ -4,10 +4,6 @@
|
|||
#include "connected.h"
|
||||
#include "transport.h"
|
||||
|
||||
int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
|
||||
{
|
||||
return check_everything_connected_with_transport(fn, quiet, cb_data, NULL);
|
||||
}
|
||||
/*
|
||||
* If we feed all the commits we want to verify to this command
|
||||
*
|
||||
|
@ -19,22 +15,27 @@ int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
|
|||
*
|
||||
* Returns 0 if everything is connected, non-zero otherwise.
|
||||
*/
|
||||
static int check_everything_connected_real(sha1_iterate_fn fn,
|
||||
int quiet,
|
||||
void *cb_data,
|
||||
struct transport *transport,
|
||||
const char *shallow_file)
|
||||
int check_connected(sha1_iterate_fn fn, void *cb_data,
|
||||
struct check_connected_options *opt)
|
||||
{
|
||||
struct child_process rev_list = CHILD_PROCESS_INIT;
|
||||
const char *argv[9];
|
||||
struct check_connected_options defaults = CHECK_CONNECTED_INIT;
|
||||
char commit[41];
|
||||
unsigned char sha1[20];
|
||||
int err = 0, ac = 0;
|
||||
int err = 0;
|
||||
struct packed_git *new_pack = NULL;
|
||||
struct transport *transport;
|
||||
size_t base_len;
|
||||
|
||||
if (fn(cb_data, sha1))
|
||||
if (!opt)
|
||||
opt = &defaults;
|
||||
transport = opt->transport;
|
||||
|
||||
if (fn(cb_data, sha1)) {
|
||||
if (opt->err_fd)
|
||||
close(opt->err_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (transport && transport->smart_options &&
|
||||
transport->smart_options->self_contained_and_connected &&
|
||||
|
@ -47,24 +48,28 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
|
|||
strbuf_release(&idx_file);
|
||||
}
|
||||
|
||||
if (shallow_file) {
|
||||
argv[ac++] = "--shallow-file";
|
||||
argv[ac++] = shallow_file;
|
||||
if (opt->shallow_file) {
|
||||
argv_array_push(&rev_list.args, "--shallow-file");
|
||||
argv_array_push(&rev_list.args, opt->shallow_file);
|
||||
}
|
||||
argv[ac++] = "rev-list";
|
||||
argv[ac++] = "--objects";
|
||||
argv[ac++] = "--stdin";
|
||||
argv[ac++] = "--not";
|
||||
argv[ac++] = "--all";
|
||||
if (quiet)
|
||||
argv[ac++] = "--quiet";
|
||||
argv[ac] = NULL;
|
||||
argv_array_push(&rev_list.args,"rev-list");
|
||||
argv_array_push(&rev_list.args, "--objects");
|
||||
argv_array_push(&rev_list.args, "--stdin");
|
||||
argv_array_push(&rev_list.args, "--not");
|
||||
argv_array_push(&rev_list.args, "--all");
|
||||
argv_array_push(&rev_list.args, "--quiet");
|
||||
if (opt->progress)
|
||||
argv_array_pushf(&rev_list.args, "--progress=%s",
|
||||
_("Checking connectivity"));
|
||||
|
||||
rev_list.argv = argv;
|
||||
rev_list.git_cmd = 1;
|
||||
rev_list.in = -1;
|
||||
rev_list.no_stdout = 1;
|
||||
rev_list.no_stderr = quiet;
|
||||
if (opt->err_fd)
|
||||
rev_list.err = opt->err_fd;
|
||||
else
|
||||
rev_list.no_stderr = opt->quiet;
|
||||
|
||||
if (start_command(&rev_list))
|
||||
return error(_("Could not run 'git rev-list'"));
|
||||
|
||||
|
@ -98,19 +103,3 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
|
|||
sigchain_pop(SIGPIPE);
|
||||
return finish_command(&rev_list) || err;
|
||||
}
|
||||
|
||||
int check_everything_connected_with_transport(sha1_iterate_fn fn,
|
||||
int quiet,
|
||||
void *cb_data,
|
||||
struct transport *transport)
|
||||
{
|
||||
return check_everything_connected_real(fn, quiet, cb_data,
|
||||
transport, NULL);
|
||||
}
|
||||
|
||||
int check_shallow_connected(sha1_iterate_fn fn, int quiet, void *cb_data,
|
||||
const char *shallow_file)
|
||||
{
|
||||
return check_everything_connected_real(fn, quiet, cb_data,
|
||||
NULL, shallow_file);
|
||||
}
|
||||
|
|
37
connected.h
37
connected.h
|
@ -10,18 +10,43 @@ struct transport;
|
|||
*/
|
||||
typedef int (*sha1_iterate_fn)(void *, unsigned char [20]);
|
||||
|
||||
/*
|
||||
* Named-arguments struct for check_connected. All arguments are
|
||||
* optional, and can be left to defaults as set by CHECK_CONNECTED_INIT.
|
||||
*/
|
||||
struct check_connected_options {
|
||||
/* Avoid printing any errors to stderr. */
|
||||
int quiet;
|
||||
|
||||
/* --shallow-file to pass to rev-list sub-process */
|
||||
const char *shallow_file;
|
||||
|
||||
/* Transport whose objects we are checking, if available. */
|
||||
struct transport *transport;
|
||||
|
||||
/*
|
||||
* If non-zero, send error messages to this descriptor rather
|
||||
* than stderr. The descriptor is closed before check_connected
|
||||
* returns.
|
||||
*/
|
||||
int err_fd;
|
||||
|
||||
/* If non-zero, show progress as we traverse the objects. */
|
||||
int progress;
|
||||
};
|
||||
|
||||
#define CHECK_CONNECTED_INIT { 0 }
|
||||
|
||||
/*
|
||||
* Make sure that our object store has all the commits necessary to
|
||||
* connect the ancestry chain to some of our existing refs, and all
|
||||
* the trees and blobs that these commits use.
|
||||
*
|
||||
* Return 0 if Ok, non zero otherwise (i.e. some missing objects)
|
||||
*
|
||||
* If "opt" is NULL, behaves as if CHECK_CONNECTED_INIT was passed.
|
||||
*/
|
||||
extern int check_everything_connected(sha1_iterate_fn, int quiet, void *cb_data);
|
||||
extern int check_shallow_connected(sha1_iterate_fn, int quiet, void *cb_data,
|
||||
const char *shallow_file);
|
||||
extern int check_everything_connected_with_transport(sha1_iterate_fn, int quiet,
|
||||
void *cb_data,
|
||||
struct transport *transport);
|
||||
int check_connected(sha1_iterate_fn fn, void *cb_data,
|
||||
struct check_connected_options *opt);
|
||||
|
||||
#endif /* CONNECTED_H */
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
This directory provides examples of Coccinelle (http://coccinelle.lip6.fr/)
|
||||
semantic patches that might be useful to developers.
|
|
@ -0,0 +1,95 @@
|
|||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- is_null_sha1(E1.hash)
|
||||
+ is_null_oid(&E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- is_null_sha1(E1->hash)
|
||||
+ is_null_oid(E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- sha1_to_hex(E1.hash)
|
||||
+ oid_to_hex(&E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- sha1_to_hex(E1->hash)
|
||||
+ oid_to_hex(E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- sha1_to_hex_r(E1.hash)
|
||||
+ oid_to_hex_r(&E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- sha1_to_hex_r(E1->hash)
|
||||
+ oid_to_hex_r(E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- hashclr(E1.hash)
|
||||
+ oidclr(&E1)
|
||||
|
||||
@@
|
||||
expression E1;
|
||||
@@
|
||||
- hashclr(E1->hash)
|
||||
+ oidclr(E1)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcmp(E1.hash, E2.hash)
|
||||
+ oidcmp(&E1, &E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcmp(E1->hash, E2->hash)
|
||||
+ oidcmp(E1, E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcmp(E1->hash, E2.hash)
|
||||
+ oidcmp(E1, &E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcmp(E1.hash, E2->hash)
|
||||
+ oidcmp(&E1, E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcpy(E1.hash, E2.hash)
|
||||
+ oidcpy(&E1, &E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcpy(E1->hash, E2->hash)
|
||||
+ oidcpy(E1, E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcpy(E1->hash, E2.hash)
|
||||
+ oidcpy(E1, &E2)
|
||||
|
||||
@@
|
||||
expression E1, E2;
|
||||
@@
|
||||
- hashcpy(E1.hash, E2->hash)
|
||||
+ oidcpy(&E1, E2)
|
|
@ -803,6 +803,50 @@ __git_find_on_cmdline ()
|
|||
done
|
||||
}
|
||||
|
||||
# Echo the value of an option set on the command line or config
|
||||
#
|
||||
# $1: short option name
|
||||
# $2: long option name including =
|
||||
# $3: list of possible values
|
||||
# $4: config string (optional)
|
||||
#
|
||||
# example:
|
||||
# result="$(__git_get_option_value "-d" "--do-something=" \
|
||||
# "yes no" "core.doSomething")"
|
||||
#
|
||||
# result is then either empty (no option set) or "yes" or "no"
|
||||
#
|
||||
# __git_get_option_value requires 3 arguments
|
||||
__git_get_option_value ()
|
||||
{
|
||||
local c short_opt long_opt val
|
||||
local result= values config_key word
|
||||
|
||||
short_opt="$1"
|
||||
long_opt="$2"
|
||||
values="$3"
|
||||
config_key="$4"
|
||||
|
||||
((c = $cword - 1))
|
||||
while [ $c -ge 0 ]; do
|
||||
word="${words[c]}"
|
||||
for val in $values; do
|
||||
if [ "$short_opt$val" = "$word" ] ||
|
||||
[ "$long_opt$val" = "$word" ]; then
|
||||
result="$val"
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
((c--))
|
||||
done
|
||||
|
||||
if [ -n "$config_key" ] && [ -z "$result" ]; then
|
||||
result="$(git --git-dir="$(__gitdir)" config "$config_key")"
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
__git_has_doubledash ()
|
||||
{
|
||||
local c=1
|
||||
|
@ -964,8 +1008,8 @@ _git_branch ()
|
|||
while [ $c -lt $cword ]; do
|
||||
i="${words[c]}"
|
||||
case "$i" in
|
||||
-d|-m) only_local_ref="y" ;;
|
||||
-r) has_r="y" ;;
|
||||
-d|--delete|-m|--move) only_local_ref="y" ;;
|
||||
-r|--remotes) has_r="y" ;;
|
||||
esac
|
||||
((c++))
|
||||
done
|
||||
|
@ -979,7 +1023,7 @@ _git_branch ()
|
|||
--color --no-color --verbose --abbrev= --no-abbrev
|
||||
--track --no-track --contains --merged --no-merged
|
||||
--set-upstream-to= --edit-description --list
|
||||
--unset-upstream
|
||||
--unset-upstream --delete --move --remotes
|
||||
"
|
||||
;;
|
||||
*)
|
||||
|
@ -1099,6 +1143,8 @@ _git_clone ()
|
|||
esac
|
||||
}
|
||||
|
||||
__git_untracked_file_modes="all no normal"
|
||||
|
||||
_git_commit ()
|
||||
{
|
||||
case "$prev" in
|
||||
|
@ -1120,7 +1166,7 @@ _git_commit ()
|
|||
return
|
||||
;;
|
||||
--untracked-files=*)
|
||||
__gitcomp "all no normal" "" "${cur##--untracked-files=}"
|
||||
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
|
@ -1159,6 +1205,8 @@ _git_describe ()
|
|||
|
||||
__git_diff_algorithms="myers minimal patience histogram"
|
||||
|
||||
__git_diff_submodule_formats="log short"
|
||||
|
||||
__git_diff_common_options="--stat --numstat --shortstat --summary
|
||||
--patch-with-stat --name-only --name-status --color
|
||||
--no-color --color-words --no-renames --check
|
||||
|
@ -1174,6 +1222,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
|
|||
--dirstat --dirstat= --dirstat-by-file
|
||||
--dirstat-by-file= --cumulative
|
||||
--diff-algorithm=
|
||||
--submodule --submodule=
|
||||
"
|
||||
|
||||
_git_diff ()
|
||||
|
@ -1185,6 +1234,10 @@ _git_diff ()
|
|||
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
|
||||
return
|
||||
;;
|
||||
--submodule=*)
|
||||
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
|
||||
--base --ours --theirs --no-index
|
||||
|
@ -1448,6 +1501,14 @@ _git_log ()
|
|||
__gitcomp "full short no" "" "${cur##--decorate=}"
|
||||
return
|
||||
;;
|
||||
--diff-algorithm=*)
|
||||
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
|
||||
return
|
||||
;;
|
||||
--submodule=*)
|
||||
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "
|
||||
$__git_log_common_options
|
||||
|
@ -1781,6 +1842,56 @@ _git_stage ()
|
|||
_git_add
|
||||
}
|
||||
|
||||
_git_status ()
|
||||
{
|
||||
local complete_opt
|
||||
local untracked_state
|
||||
|
||||
case "$cur" in
|
||||
--ignore-submodules=*)
|
||||
__gitcomp "none untracked dirty all" "" "${cur##--ignore-submodules=}"
|
||||
return
|
||||
;;
|
||||
--untracked-files=*)
|
||||
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
|
||||
return
|
||||
;;
|
||||
--column=*)
|
||||
__gitcomp "
|
||||
always never auto column row plain dense nodense
|
||||
" "" "${cur##--column=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "
|
||||
--short --branch --porcelain --long --verbose
|
||||
--untracked-files= --ignore-submodules= --ignored
|
||||
--column= --no-column
|
||||
"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
untracked_state="$(__git_get_option_value "-u" "--untracked-files=" \
|
||||
"$__git_untracked_file_modes" "status.showUntrackedFiles")"
|
||||
|
||||
case "$untracked_state" in
|
||||
no)
|
||||
# --ignored option does not matter
|
||||
complete_opt=
|
||||
;;
|
||||
all|normal|*)
|
||||
complete_opt="--cached --directory --no-empty-directory --others"
|
||||
|
||||
if [ -n "$(__git_find_on_cmdline "--ignored")" ]; then
|
||||
complete_opt="$complete_opt --ignored --exclude=*"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
__git_complete_index_file "$complete_opt"
|
||||
}
|
||||
|
||||
__git_config_get_set_variables ()
|
||||
{
|
||||
local prevword word config_file= c=$cword
|
||||
|
@ -2086,6 +2197,7 @@ _git_config ()
|
|||
format.attach
|
||||
format.cc
|
||||
format.coverLetter
|
||||
format.from
|
||||
format.headers
|
||||
format.numbered
|
||||
format.pretty
|
||||
|
@ -2360,6 +2472,10 @@ _git_show ()
|
|||
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
|
||||
return
|
||||
;;
|
||||
--submodule=*)
|
||||
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "--pretty= --format= --abbrev-commit --oneline
|
||||
--show-signature
|
||||
|
@ -2596,6 +2712,32 @@ _git_whatchanged ()
|
|||
_git_log
|
||||
}
|
||||
|
||||
_git_worktree ()
|
||||
{
|
||||
local subcommands="add list lock prune unlock"
|
||||
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
||||
if [ -z "$subcommand" ]; then
|
||||
__gitcomp "$subcommands"
|
||||
else
|
||||
case "$subcommand,$cur" in
|
||||
add,--*)
|
||||
__gitcomp "--detach"
|
||||
;;
|
||||
list,--*)
|
||||
__gitcomp "--porcelain"
|
||||
;;
|
||||
lock,--*)
|
||||
__gitcomp "--reason"
|
||||
;;
|
||||
prune,--*)
|
||||
__gitcomp "--dry-run --expire --verbose"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
__git_main ()
|
||||
{
|
||||
local i c=1 command __git_dir
|
||||
|
|
|
@ -29,7 +29,7 @@ Obviously this trivial case isn't that interesting; you could just open
|
|||
`foo.c` yourself. But when you have many changes scattered across a
|
||||
project, you can use the editor's support to "jump" from point to point.
|
||||
|
||||
Git-jump can generate three types of interesting lists:
|
||||
Git-jump can generate four types of interesting lists:
|
||||
|
||||
1. The beginning of any diff hunks.
|
||||
|
||||
|
@ -37,6 +37,8 @@ Git-jump can generate three types of interesting lists:
|
|||
|
||||
3. Any grep matches.
|
||||
|
||||
4. Any whitespace errors detected by `git diff --check`.
|
||||
|
||||
|
||||
Using git-jump
|
||||
--------------
|
||||
|
@ -83,7 +85,7 @@ complete list of files and line numbers for each match.
|
|||
Limitations
|
||||
-----------
|
||||
|
||||
This scripts was written and tested with vim. Given that the quickfix
|
||||
This script was written and tested with vim. Given that the quickfix
|
||||
format is the same as what gcc produces, I expect emacs users have a
|
||||
similar feature for iterating through the list, but I know nothing about
|
||||
how to activate it.
|
||||
|
|
|
@ -12,6 +12,8 @@ diff: elements are diff hunks. Arguments are given to diff.
|
|||
merge: elements are merge conflicts. Arguments are ignored.
|
||||
|
||||
grep: elements are grep hits. Arguments are given to grep.
|
||||
|
||||
ws: elements are whitespace errors. Arguments are given to diff --check.
|
||||
EOF
|
||||
}
|
||||
|
||||
|
@ -25,7 +27,7 @@ mode_diff() {
|
|||
perl -ne '
|
||||
if (m{^\+\+\+ (.*)}) { $file = $1; next }
|
||||
defined($file) or next;
|
||||
if (m/^@@ .*\+(\d+)/) { $line = $1; next }
|
||||
if (m/^@@ .*?\+(\d+)/) { $line = $1; next }
|
||||
defined($line) or next;
|
||||
if (/^ /) { $line++; next }
|
||||
if (/^[-+]\s*(.*)/) {
|
||||
|
@ -55,6 +57,10 @@ mode_grep() {
|
|||
'
|
||||
}
|
||||
|
||||
mode_ws() {
|
||||
git diff --check "$@"
|
||||
}
|
||||
|
||||
if test $# -lt 1; then
|
||||
usage >&2
|
||||
exit 1
|
||||
|
|
|
@ -1,3 +1,62 @@
|
|||
Release 1.4.0
|
||||
=============
|
||||
|
||||
New features to troubleshoot a git-multimail installation
|
||||
---------------------------------------------------------
|
||||
|
||||
* One can now perform a basic check of git-multimail's setup by
|
||||
running the hook with the environment variable
|
||||
GIT_MULTIMAIL_CHECK_SETUP set to a non-empty string. See
|
||||
doc/troubleshooting.rst for details.
|
||||
|
||||
* A new log files system was added. See the multimailhook.logFile,
|
||||
multimailhook.errorLogFile and multimailhook.debugLogFile variables.
|
||||
|
||||
* git_multimail.py can now be made more verbose using
|
||||
multimailhook.verbose.
|
||||
|
||||
* A new option --check-ref-filter is now available to help debugging
|
||||
the refFilter* options.
|
||||
|
||||
Formatting emails
|
||||
-----------------
|
||||
|
||||
* Formatting of emails was made slightly more compact, to reduce the
|
||||
odds of having long subject lines truncated or wrapped in short list
|
||||
of commits.
|
||||
|
||||
* multimailhook.emailPrefix may now use the '%(repo_shortname)s'
|
||||
placeholder for the repository's short name.
|
||||
|
||||
* A new option multimailhook.subjectMaxLength is available to truncate
|
||||
overly long subject lines.
|
||||
|
||||
Bug fixes and minor changes
|
||||
---------------------------
|
||||
|
||||
* Options refFilterDoSendRegex and refFilterDontSendRegex were
|
||||
essentially broken. They should work now.
|
||||
|
||||
* The behavior when both refFilter{Do,Dont}SendRegex and
|
||||
refFilter{Exclusion,Inclusion}Regex are set have been slightly
|
||||
changed. Exclusion/Inclusion is now strictly stronger than
|
||||
DoSend/DontSend.
|
||||
|
||||
* The management of precedence when a setting can be computed in
|
||||
multiple ways has been considerably refactored and modified.
|
||||
multimailhook.from and multimailhook.reponame now have precedence
|
||||
over the environment-specific settings ($GL_REPO/$GL_USER for
|
||||
gitolite, --stash-user/repo for Stash, --submitter/--project for
|
||||
Gerrit).
|
||||
|
||||
* The coverage of the testsuite has been considerably improved. All
|
||||
configuration variables now appear at least once in the testsuite.
|
||||
|
||||
This version was tested with Python 2.6 to 3.5. It also mostly works
|
||||
with Python 2.4, but there is one known breakage in the testsuite
|
||||
related to non-ascii characters. It was tested with Git
|
||||
1.7.10.406.gdc801, 1.8.5.6, 2.1.4, and 2.10.0.rc0.1.g07c9292.
|
||||
|
||||
Release 1.3.1 (bugfix-only release)
|
||||
===================================
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ Contributing
|
|||
git-multimail is an open-source project, built by volunteers. We would
|
||||
welcome your help!
|
||||
|
||||
The current maintainers are Michael Haggerty <mhagger@alum.mit.edu>
|
||||
and Matthieu Moy <matthieu.moy@grenoble-inp.fr>.
|
||||
The current maintainers are Matthieu Moy
|
||||
<matthieu.moy@grenoble-inp.fr> and Michael Haggerty
|
||||
<mhagger@alum.mit.edu>.
|
||||
|
||||
Please note that although a copy of git-multimail is distributed in
|
||||
the "contrib" section of the main Git project, development takes place
|
||||
|
@ -22,6 +23,10 @@ to the maintainers). Please sign off your patches as per the `Git
|
|||
project practice
|
||||
<https://github.com/git/git/blob/master/Documentation/SubmittingPatches#L234>`__.
|
||||
|
||||
Please vote for issues you would like to be addressed in priority
|
||||
(click "add your reaction" and then the "+1" thumbs-up button on the
|
||||
GitHub issue).
|
||||
|
||||
General discussion of git-multimail can take place on the main `Git
|
||||
mailing list`_.
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
git-multimail 1.3.1
|
||||
===================
|
||||
git-multimail version 1.4.0
|
||||
===========================
|
||||
|
||||
.. image:: https://travis-ci.org/git-multimail/git-multimail.svg?branch=master
|
||||
:target: https://travis-ci.org/git-multimail/git-multimail
|
||||
|
||||
git-multimail is a tool for sending notification emails on pushes to a
|
||||
Git repository. It includes a Python module called git_multimail.py,
|
||||
Git repository. It includes a Python module called ``git_multimail.py``,
|
||||
which can either be used as a hook script directly or can be imported
|
||||
as a Python module into another script.
|
||||
|
||||
|
@ -93,20 +93,20 @@ Requirements
|
|||
Invocation
|
||||
----------
|
||||
|
||||
git_multimail.py is designed to be used as a ``post-receive`` hook in a
|
||||
``git_multimail.py`` is designed to be used as a ``post-receive`` hook in a
|
||||
Git repository (see githooks(5)). Link or copy it to
|
||||
$GIT_DIR/hooks/post-receive within the repository for which email
|
||||
notifications are desired. Usually it should be installed on the
|
||||
central repository for a project, to which all commits are eventually
|
||||
pushed.
|
||||
|
||||
For use on pre-v1.5.1 Git servers, git_multimail.py can also work as
|
||||
For use on pre-v1.5.1 Git servers, ``git_multimail.py`` can also work as
|
||||
an ``update`` hook, taking its arguments on the command line. To use
|
||||
this script in this manner, link or copy it to $GIT_DIR/hooks/update.
|
||||
Please note that the script is not completely reliable in this mode
|
||||
[2]_.
|
||||
[1]_.
|
||||
|
||||
Alternatively, git_multimail.py can be imported as a Python module
|
||||
Alternatively, ``git_multimail.py`` can be imported as a Python module
|
||||
into your own Python post-receive script. This method is a bit more
|
||||
work, but allows the behavior of the hook to be customized using
|
||||
arbitrary Python code. For example, you can use a custom environment
|
||||
|
@ -122,7 +122,7 @@ arbitrary Python code. For example, you can use a custom environment
|
|||
|
||||
Or you can change how emails are sent by writing your own Mailer
|
||||
class. The ``post-receive`` script in this directory demonstrates how
|
||||
to use git_multimail.py as a Python module. (If you make interesting
|
||||
to use ``git_multimail.py`` as a Python module. (If you make interesting
|
||||
changes of this type, please consider sharing them with the
|
||||
community.)
|
||||
|
||||
|
@ -151,7 +151,10 @@ multimailhook.environment
|
|||
the repository name is derived from the repository's path.
|
||||
|
||||
gitolite
|
||||
the username of the pusher is read from $GL_USER, the repository
|
||||
Environment to use when ``git-multimail`` is ran as a gitolite_
|
||||
hook.
|
||||
|
||||
The username of the pusher is read from $GL_USER, the repository
|
||||
name is read from $GL_REPO, and the From: header value is
|
||||
optionally read from gitolite.conf (see multimailhook.from).
|
||||
|
||||
|
@ -294,7 +297,7 @@ multimailhook.htmlInIntro, multimailhook.htmlInFooter
|
|||
like ``<a href="foo">link</a>``, the reader will see the HTML
|
||||
source code and not a proper link.
|
||||
|
||||
Set ``multimailhook.htmlInIntro`` to true to allow writting HTML
|
||||
Set ``multimailhook.htmlInIntro`` to true to allow writing HTML
|
||||
formatting in introduction templates. Similarly, set
|
||||
``multimailhook.htmlInFooter`` for HTML in the footer.
|
||||
|
||||
|
@ -444,7 +447,9 @@ multimailhook.emailPrefix
|
|||
email filtering (though filtering based on the X-Git-* email
|
||||
headers is probably more robust). Default is the short name of
|
||||
the repository in square brackets; e.g., ``[myrepo]``. Set this
|
||||
value to the empty string to suppress the email prefix.
|
||||
value to the empty string to suppress the email prefix. You may
|
||||
use the placeholder ``%(repo_shortname)s`` for the short name of
|
||||
the repository.
|
||||
|
||||
multimailhook.emailMaxLines
|
||||
The maximum number of lines that should be included in the body of
|
||||
|
@ -461,6 +466,17 @@ multimailhook.emailMaxLineLength
|
|||
lines, the diffs are probably unreadable anyway. To disable line
|
||||
truncation, set this option to 0.
|
||||
|
||||
multimailhook.subjectMaxLength
|
||||
The maximum length of the subject line (i.e. the ``oneline`` field
|
||||
in templates, not including the prefix). Lines longer than this
|
||||
limit are truncated to this length with a trailing ``[...]`` added
|
||||
to indicate the missing text. This option The default is to use
|
||||
``multimailhook.emailMaxLineLength``. This option avoids sending
|
||||
emails with overly long subject lines, but should not be needed if
|
||||
the commit messages follow the Git convention (one short subject
|
||||
line, then a blank line, then the message body). To disable line
|
||||
truncation, set this option to 0.
|
||||
|
||||
multimailhook.maxCommitEmails
|
||||
The maximum number of commit emails to send for a given change.
|
||||
When the number of patches is larger that this value, only the
|
||||
|
@ -474,12 +490,15 @@ multimailhook.emailStrictUTF8
|
|||
not valid UTF-8 are converted to the Unicode replacement
|
||||
character, U+FFFD. The default is `true`.
|
||||
|
||||
This option is ineffective with Python 3, where non-UTF-8
|
||||
characters are unconditionally replaced.
|
||||
|
||||
multimailhook.diffOpts
|
||||
Options passed to ``git diff-tree`` when generating the summary
|
||||
information for ReferenceChange emails. Default is ``--stat
|
||||
--summary --find-copies-harder``. Add -p to those options to
|
||||
include a unified diff of changes in addition to the usual summary
|
||||
output. Shell quoting is allowed; see multimailhook.logOpts for
|
||||
output. Shell quoting is allowed; see ``multimailhook.logOpts`` for
|
||||
details.
|
||||
|
||||
multimailhook.graphOpts
|
||||
|
@ -516,7 +535,7 @@ multimailhook.commitLogOpts
|
|||
|
||||
multimailhook.dateSubstitute
|
||||
String to use as a substitute for ``Date:`` in the output of ``git
|
||||
log`` while formatting commit messages. This is usefull to avoid
|
||||
log`` while formatting commit messages. This is useful to avoid
|
||||
emitting a line that can be interpreted by mailers as the start of
|
||||
a cited message (Zimbra webmail in particular). Defaults to
|
||||
``CommitDate:``. Set to an empty string or ``none`` to deactivate
|
||||
|
@ -564,6 +583,8 @@ multimailhook.refFilterInclusionRegex, multimailhook.refFilterExclusionRegex, mu
|
|||
the user-interface is not stable yet (in particular, the option
|
||||
names may change). If you want to participate in stabilizing the
|
||||
feature, please contact the maintainers and/or send pull-requests.
|
||||
If you are happy with the current shape of the feature, please
|
||||
report it too.
|
||||
|
||||
Regular expressions that can be used to limit refs for which email
|
||||
updates will be sent. It is an error to specify both an inclusion
|
||||
|
@ -613,6 +634,32 @@ multimailhook.refFilterInclusionRegex, multimailhook.refFilterExclusionRegex, mu
|
|||
[multimailhook]
|
||||
refFilterExclusionRegex = ^refs/tags/|^refs/heads/master$
|
||||
|
||||
``refFilterInclusionRegex`` and ``refFilterExclusionRegex`` are
|
||||
strictly stronger than ``refFilterDoSendRegex`` and
|
||||
``refFilterDontSendRegex``. In other words, adding a ref to a
|
||||
DoSend/DontSend regex has no effect if it is already excluded by a
|
||||
Exclusion/Inclusion regex.
|
||||
|
||||
multimailhook.logFile, multimailhook.errorLogFile, multimailhook.debugLogFile
|
||||
|
||||
When set, these variable designate path to files where
|
||||
git-multimail will log some messages. Normal messages and error
|
||||
messages are sent to ``logFile``, and error messages are also sent
|
||||
to ``errorLogFile``. Debug messages and all other messages are
|
||||
sent to ``debugLogFile``. The recommended way is to set only one
|
||||
of these variables, but it is also possible to set several of them
|
||||
(part of the information is then duplicated in several log files,
|
||||
for example errors are duplicated to all log files).
|
||||
|
||||
Relative path are relative to the Git repository where the push is
|
||||
done.
|
||||
|
||||
multimailhook.verbose
|
||||
|
||||
Verbosity level of git-multimail on its standard output. By
|
||||
default, show only error and info messages. If set to true, show
|
||||
also debug messages.
|
||||
|
||||
Email filtering aids
|
||||
--------------------
|
||||
|
||||
|
@ -628,8 +675,8 @@ Customizing email contents
|
|||
|
||||
git-multimail mostly generates emails by expanding templates. The
|
||||
templates can be customized. To avoid the need to edit
|
||||
git_multimail.py directly, the preferred way to change the templates
|
||||
is to write a separate Python script that imports git_multimail.py as
|
||||
``git_multimail.py`` directly, the preferred way to change the templates
|
||||
is to write a separate Python script that imports ``git_multimail.py`` as
|
||||
a module, then replaces the templates in place. See the provided
|
||||
post-receive script for an example of how this is done.
|
||||
|
||||
|
@ -645,8 +692,8 @@ GenericEnvironment
|
|||
a stand-alone Git repository.
|
||||
|
||||
GitoliteEnvironment
|
||||
a Git repository that is managed by gitolite
|
||||
[3]_. For such repositories, the identity of the pusher is read from
|
||||
a Git repository that is managed by gitolite_. For such
|
||||
repositories, the identity of the pusher is read from
|
||||
environment variable $GL_USER, the name of the repository is read
|
||||
from $GL_REPO (if it is not overridden by multimailhook.reponame),
|
||||
and the From: header value is optionally read from gitolite.conf
|
||||
|
@ -662,7 +709,7 @@ option to the script.
|
|||
If you need to customize the script in ways that are not supported by
|
||||
the existing environments, you can define your own environment class
|
||||
class using arbitrary Python code. To do so, you need to import
|
||||
git_multimail.py as a Python module, as demonstrated by the example
|
||||
``git_multimail.py`` as a Python module, as demonstrated by the example
|
||||
post-receive script. Then implement your environment class; it should
|
||||
usually inherit from one of the existing Environment classes and
|
||||
possibly one or more of the EnvironmentMixin classes. Then set the
|
||||
|
@ -690,9 +737,7 @@ contribute to git-multimail.
|
|||
Footnotes
|
||||
---------
|
||||
|
||||
.. [1] http://www.python.org/dev/peps/pep-0394/
|
||||
|
||||
.. [2] Because of the way information is passed to update hooks, the
|
||||
.. [1] Because of the way information is passed to update hooks, the
|
||||
script's method of determining whether a commit has already
|
||||
been seen does not work when it is used as an ``update`` script.
|
||||
In particular, no notification email will be generated for a
|
||||
|
@ -700,4 +745,4 @@ Footnotes
|
|||
push. A workaround is to use --force-send to force sending the
|
||||
emails.
|
||||
|
||||
.. [3] https://github.com/sitaramc/gitolite
|
||||
.. _gitolite: https://github.com/sitaramc/gitolite
|
||||
|
|
|
@ -6,10 +6,10 @@ website:
|
|||
https://github.com/git-multimail/git-multimail
|
||||
|
||||
The version in this directory was obtained from the upstream project
|
||||
on May 13 2016 and consists of the "git-multimail" subdirectory from
|
||||
on August 17 2016 and consists of the "git-multimail" subdirectory from
|
||||
revision
|
||||
|
||||
3ce5470d4abf7251604cbf64e73a962e1b617f5e refs/tags/1.3.1
|
||||
07b1cb6bfd7be156c62e1afa17cae13b850a869f refs/tags/1.4.0
|
||||
|
||||
Please see the README file in this directory for information about how
|
||||
to report bugs or contribute to git-multimail.
|
||||
|
|
|
@ -1,6 +1,40 @@
|
|||
Troubleshooting issues with git-multimail: a FAQ
|
||||
================================================
|
||||
|
||||
How to check that git-multimail is properly set up?
|
||||
---------------------------------------------------
|
||||
|
||||
Since version 1.4.0, git-multimail allows a simple self-checking of
|
||||
its configuration: run it with the environment variable
|
||||
``GIT_MULTIMAIL_CHECK_SETUP`` set to a non-empty string. You should
|
||||
get something like this::
|
||||
|
||||
$ GIT_MULTIMAIL_CHECK_SETUP=true /home/moy/dev/git-multimail/git-multimail/git_multimail.py
|
||||
Environment values:
|
||||
administrator : 'the administrator of this repository'
|
||||
charset : 'utf-8'
|
||||
emailprefix : '[git-multimail] '
|
||||
fqdn : 'anie'
|
||||
projectdesc : 'UNNAMED PROJECT'
|
||||
pusher : 'moy'
|
||||
repo_path : '/home/moy/dev/git-multimail'
|
||||
repo_shortname : 'git-multimail'
|
||||
|
||||
Now, checking that git-multimail's standard input is properly set ...
|
||||
Please type some text and then press Return
|
||||
foo
|
||||
You have just entered:
|
||||
foo
|
||||
git-multimail seems properly set up.
|
||||
|
||||
If you forgot to set an important variable, you may get instead::
|
||||
|
||||
$ GIT_MULTIMAIL_CHECK_SETUP=true /home/moy/dev/git-multimail/git-multimail/git_multimail.py
|
||||
No email recipients configured!
|
||||
|
||||
Do not set ``$GIT_MULTIMAIL_CHECK_SETUP`` other than for testing your
|
||||
configuration: it would disable the hook completely.
|
||||
|
||||
Git is not using the right address in the From/To/Reply-To field
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,7 +19,7 @@
|
|||
[InputOutput::RequireCheckedSyscalls]
|
||||
functions = open say close
|
||||
|
||||
# This rules demands to add a dependancy for the Readonly module. This is not
|
||||
# This rule demands to add a dependency for the Readonly module. This is not
|
||||
# wished.
|
||||
[-ValuesAndExpressions::ProhibitConstantPragma]
|
||||
|
||||
|
|
|
@ -963,7 +963,7 @@ sub mw_upload_file {
|
|||
print {*STDERR} "Check the configuration of file uploads in your mediawiki.\n";
|
||||
return $newrevid;
|
||||
}
|
||||
# Deleting and uploading a file requires a priviledged user
|
||||
# Deleting and uploading a file requires a privileged user
|
||||
if ($file_deleted) {
|
||||
$mediawiki = connect_maybe($mediawiki, $remotename, $url);
|
||||
my $query = {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -948,7 +948,7 @@ test_expect_success 'split a new subtree without --onto option' '
|
|||
|
||||
# also test that we still can split out an entirely new subtree
|
||||
# if the parent of the first commit in the tree is not empty,
|
||||
# then the new subtree has accidently been attached to something
|
||||
# then the new subtree has accidentally been attached to something
|
||||
git subtree split --prefix="sub dir2" --branch subproj2-br &&
|
||||
check_equal "$(git log --pretty=format:%P -1 subproj2-br)" ""
|
||||
)
|
||||
|
|
97
convert.c
97
convert.c
|
@ -189,33 +189,25 @@ static enum eol output_eol(enum crlf_action crlf_action)
|
|||
}
|
||||
|
||||
static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
|
||||
struct text_stat *stats, enum safe_crlf checksafe)
|
||||
struct text_stat *old_stats, struct text_stat *new_stats,
|
||||
enum safe_crlf checksafe)
|
||||
{
|
||||
if (!checksafe)
|
||||
return;
|
||||
|
||||
if (output_eol(crlf_action) == EOL_LF) {
|
||||
if (old_stats->crlf && !new_stats->crlf ) {
|
||||
/*
|
||||
* CRLFs would not be restored by checkout:
|
||||
* check if we'd remove CRLFs
|
||||
* CRLFs would not be restored by checkout
|
||||
*/
|
||||
if (stats->crlf) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("CRLF would be replaced by LF in %s.", path);
|
||||
}
|
||||
} else if (output_eol(crlf_action) == EOL_CRLF) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("CRLF would be replaced by LF in %s.", path);
|
||||
} else if (old_stats->lonelf && !new_stats->lonelf ) {
|
||||
/*
|
||||
* CRLFs would be added by checkout:
|
||||
* check if we have "naked" LFs
|
||||
* CRLFs would be added by checkout
|
||||
*/
|
||||
if (stats->lonelf) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("LF would be replaced by CRLF in %s", path);
|
||||
}
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("LF would be replaced by CRLF in %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,12 +225,35 @@ static int has_cr_in_index(const char *path)
|
|||
return has_cr;
|
||||
}
|
||||
|
||||
static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,
|
||||
enum crlf_action crlf_action)
|
||||
{
|
||||
if (output_eol(crlf_action) != EOL_CRLF)
|
||||
return 0;
|
||||
/* No "naked" LF? Nothing to convert, regardless. */
|
||||
if (!stats->lonelf)
|
||||
return 0;
|
||||
|
||||
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
||||
/* If we have any CR or CRLF line endings, we do not touch it */
|
||||
/* This is the new safer autocrlf-handling */
|
||||
if (stats->lonecr || stats->crlf)
|
||||
return 0;
|
||||
|
||||
if (convert_is_binary(len, stats))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int crlf_to_git(const char *path, const char *src, size_t len,
|
||||
struct strbuf *buf,
|
||||
enum crlf_action crlf_action, enum safe_crlf checksafe)
|
||||
{
|
||||
struct text_stat stats;
|
||||
char *dst;
|
||||
int convert_crlf_into_lf;
|
||||
|
||||
if (crlf_action == CRLF_BINARY ||
|
||||
(src && !len))
|
||||
|
@ -252,6 +267,8 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
|||
return 1;
|
||||
|
||||
gather_stats(src, len, &stats);
|
||||
/* Optimization: No CRLF? Nothing to convert, regardless. */
|
||||
convert_crlf_into_lf = !!stats.crlf;
|
||||
|
||||
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
||||
if (convert_is_binary(len, &stats))
|
||||
|
@ -263,12 +280,24 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
|||
if (checksafe == SAFE_CRLF_RENORMALIZE)
|
||||
checksafe = SAFE_CRLF_FALSE;
|
||||
else if (has_cr_in_index(path))
|
||||
return 0;
|
||||
convert_crlf_into_lf = 0;
|
||||
}
|
||||
check_safe_crlf(path, crlf_action, &stats, checksafe);
|
||||
|
||||
/* Optimization: No CRLF? Nothing to convert, regardless. */
|
||||
if (!stats.crlf)
|
||||
if (checksafe && len) {
|
||||
struct text_stat new_stats;
|
||||
memcpy(&new_stats, &stats, sizeof(new_stats));
|
||||
/* simulate "git add" */
|
||||
if (convert_crlf_into_lf) {
|
||||
new_stats.lonelf += new_stats.crlf;
|
||||
new_stats.crlf = 0;
|
||||
}
|
||||
/* simulate "git checkout" */
|
||||
if (will_convert_lf_to_crlf(len, &new_stats, crlf_action)) {
|
||||
new_stats.crlf += new_stats.lonelf;
|
||||
new_stats.lonelf = 0;
|
||||
}
|
||||
check_safe_crlf(path, crlf_action, &stats, &new_stats, checksafe);
|
||||
}
|
||||
if (!convert_crlf_into_lf)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -314,21 +343,9 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,
|
|||
return 0;
|
||||
|
||||
gather_stats(src, len, &stats);
|
||||
|
||||
/* No "naked" LF? Nothing to convert, regardless. */
|
||||
if (!stats.lonelf)
|
||||
if (!will_convert_lf_to_crlf(len, &stats, crlf_action))
|
||||
return 0;
|
||||
|
||||
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
||||
/* If we have any CR or CRLF line endings, we do not touch it */
|
||||
/* This is the new safer autocrlf-handling */
|
||||
if (stats.lonecr || stats.crlf )
|
||||
return 0;
|
||||
|
||||
if (convert_is_binary(len, &stats))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* are we "faking" in place editing ? */
|
||||
if (src == buf->buf)
|
||||
to_free = strbuf_detach(buf, NULL);
|
||||
|
|
117
diff.c
117
diff.c
|
@ -1933,8 +1933,8 @@ static void show_dirstat(struct diff_options *options)
|
|||
|
||||
name = p->two->path ? p->two->path : p->one->path;
|
||||
|
||||
if (p->one->sha1_valid && p->two->sha1_valid)
|
||||
content_changed = hashcmp(p->one->sha1, p->two->sha1);
|
||||
if (p->one->oid_valid && p->two->oid_valid)
|
||||
content_changed = oidcmp(&p->one->oid, &p->two->oid);
|
||||
else
|
||||
content_changed = 1;
|
||||
|
||||
|
@ -2306,7 +2306,8 @@ static void builtin_diff(const char *name_a,
|
|||
const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
|
||||
show_submodule_summary(o->file, one->path ? one->path : two->path,
|
||||
line_prefix,
|
||||
one->sha1, two->sha1, two->dirty_submodule,
|
||||
one->oid.hash, two->oid.hash,
|
||||
two->dirty_submodule,
|
||||
meta, del, add, reset);
|
||||
return;
|
||||
}
|
||||
|
@ -2384,7 +2385,7 @@ static void builtin_diff(const char *name_a,
|
|||
if (!one->data && !two->data &&
|
||||
S_ISREG(one->mode) && S_ISREG(two->mode) &&
|
||||
!DIFF_OPT_TST(o, BINARY)) {
|
||||
if (!hashcmp(one->sha1, two->sha1)) {
|
||||
if (!oidcmp(&one->oid, &two->oid)) {
|
||||
if (must_show_header)
|
||||
fprintf(o->file, "%s", header.buf);
|
||||
goto free_ab_and_return;
|
||||
|
@ -2505,7 +2506,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
|||
return;
|
||||
}
|
||||
|
||||
same_contents = !hashcmp(one->sha1, two->sha1);
|
||||
same_contents = !oidcmp(&one->oid, &two->oid);
|
||||
|
||||
if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
|
||||
data->is_binary = 1;
|
||||
|
@ -2638,8 +2639,8 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
|
|||
{
|
||||
if (mode) {
|
||||
spec->mode = canon_mode(mode);
|
||||
hashcpy(spec->sha1, sha1);
|
||||
spec->sha1_valid = sha1_valid;
|
||||
hashcpy(spec->oid.hash, sha1);
|
||||
spec->oid_valid = sha1_valid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2728,7 +2729,8 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
|
|||
if (s->dirty_submodule)
|
||||
dirty = "-dirty";
|
||||
|
||||
strbuf_addf(&buf, "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
|
||||
strbuf_addf(&buf, "Subproject commit %s%s\n",
|
||||
oid_to_hex(&s->oid), dirty);
|
||||
s->size = buf.len;
|
||||
if (size_only) {
|
||||
s->data = NULL;
|
||||
|
@ -2771,8 +2773,8 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
|
|||
if (S_ISGITLINK(s->mode))
|
||||
return diff_populate_gitlink(s, size_only);
|
||||
|
||||
if (!s->sha1_valid ||
|
||||
reuse_worktree_file(s->path, s->sha1, 0)) {
|
||||
if (!s->oid_valid ||
|
||||
reuse_worktree_file(s->path, s->oid.hash, 0)) {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
@ -2829,9 +2831,10 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
|
|||
else {
|
||||
enum object_type type;
|
||||
if (size_only || (flags & CHECK_BINARY)) {
|
||||
type = sha1_object_info(s->sha1, &s->size);
|
||||
type = sha1_object_info(s->oid.hash, &s->size);
|
||||
if (type < 0)
|
||||
die("unable to read %s", sha1_to_hex(s->sha1));
|
||||
die("unable to read %s",
|
||||
oid_to_hex(&s->oid));
|
||||
if (size_only)
|
||||
return 0;
|
||||
if (s->size > big_file_threshold && s->is_binary == -1) {
|
||||
|
@ -2839,9 +2842,9 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
s->data = read_sha1_file(s->sha1, &type, &s->size);
|
||||
s->data = read_sha1_file(s->oid.hash, &type, &s->size);
|
||||
if (!s->data)
|
||||
die("unable to read %s", sha1_to_hex(s->sha1));
|
||||
die("unable to read %s", oid_to_hex(&s->oid));
|
||||
s->should_free = 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -2870,7 +2873,7 @@ void diff_free_filespec_data(struct diff_filespec *s)
|
|||
static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
|
||||
void *blob,
|
||||
unsigned long size,
|
||||
const unsigned char *sha1,
|
||||
const struct object_id *oid,
|
||||
int mode)
|
||||
{
|
||||
int fd;
|
||||
|
@ -2895,7 +2898,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
|
|||
die_errno("unable to write temp-file");
|
||||
close_tempfile(&temp->tempfile);
|
||||
temp->name = get_tempfile_path(&temp->tempfile);
|
||||
sha1_to_hex_r(temp->hex, sha1);
|
||||
oid_to_hex_r(temp->hex, oid);
|
||||
xsnprintf(temp->mode, sizeof(temp->mode), "%06o", mode);
|
||||
strbuf_release(&buf);
|
||||
strbuf_release(&template);
|
||||
|
@ -2919,8 +2922,8 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
|
|||
}
|
||||
|
||||
if (!S_ISGITLINK(one->mode) &&
|
||||
(!one->sha1_valid ||
|
||||
reuse_worktree_file(name, one->sha1, 1))) {
|
||||
(!one->oid_valid ||
|
||||
reuse_worktree_file(name, one->oid.hash, 1))) {
|
||||
struct stat st;
|
||||
if (lstat(name, &st) < 0) {
|
||||
if (errno == ENOENT)
|
||||
|
@ -2932,19 +2935,19 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
|
|||
if (strbuf_readlink(&sb, name, st.st_size) < 0)
|
||||
die_errno("readlink(%s)", name);
|
||||
prep_temp_blob(name, temp, sb.buf, sb.len,
|
||||
(one->sha1_valid ?
|
||||
one->sha1 : null_sha1),
|
||||
(one->sha1_valid ?
|
||||
(one->oid_valid ?
|
||||
&one->oid : &null_oid),
|
||||
(one->oid_valid ?
|
||||
one->mode : S_IFLNK));
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
else {
|
||||
/* we can borrow from the file in the work tree */
|
||||
temp->name = name;
|
||||
if (!one->sha1_valid)
|
||||
if (!one->oid_valid)
|
||||
sha1_to_hex_r(temp->hex, null_sha1);
|
||||
else
|
||||
sha1_to_hex_r(temp->hex, one->sha1);
|
||||
sha1_to_hex_r(temp->hex, one->oid.hash);
|
||||
/* Even though we may sometimes borrow the
|
||||
* contents from the work tree, we always want
|
||||
* one->mode. mode is trustworthy even when
|
||||
|
@ -2959,7 +2962,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
|
|||
if (diff_populate_filespec(one, 0))
|
||||
die("cannot read data blob for %s", one->path);
|
||||
prep_temp_blob(name, temp, one->data, one->size,
|
||||
one->sha1, one->mode);
|
||||
&one->oid, one->mode);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
@ -3072,7 +3075,7 @@ static void fill_metainfo(struct strbuf *msg,
|
|||
default:
|
||||
*must_show_header = 0;
|
||||
}
|
||||
if (one && two && hashcmp(one->sha1, two->sha1)) {
|
||||
if (one && two && oidcmp(&one->oid, &two->oid)) {
|
||||
int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
|
||||
|
||||
if (DIFF_OPT_TST(o, BINARY)) {
|
||||
|
@ -3082,8 +3085,8 @@ static void fill_metainfo(struct strbuf *msg,
|
|||
abbrev = 40;
|
||||
}
|
||||
strbuf_addf(msg, "%s%sindex %s..", line_prefix, set,
|
||||
find_unique_abbrev(one->sha1, abbrev));
|
||||
strbuf_addstr(msg, find_unique_abbrev(two->sha1, abbrev));
|
||||
find_unique_abbrev(one->oid.hash, abbrev));
|
||||
strbuf_addstr(msg, find_unique_abbrev(two->oid.hash, abbrev));
|
||||
if (one->mode == two->mode)
|
||||
strbuf_addf(msg, " %06o", one->mode);
|
||||
strbuf_addf(msg, "%s\n", reset);
|
||||
|
@ -3138,20 +3141,20 @@ static void run_diff_cmd(const char *pgm,
|
|||
static void diff_fill_sha1_info(struct diff_filespec *one)
|
||||
{
|
||||
if (DIFF_FILE_VALID(one)) {
|
||||
if (!one->sha1_valid) {
|
||||
if (!one->oid_valid) {
|
||||
struct stat st;
|
||||
if (one->is_stdin) {
|
||||
hashcpy(one->sha1, null_sha1);
|
||||
oidclr(&one->oid);
|
||||
return;
|
||||
}
|
||||
if (lstat(one->path, &st) < 0)
|
||||
die_errno("stat '%s'", one->path);
|
||||
if (index_path(one->sha1, one->path, &st, 0))
|
||||
if (index_path(one->oid.hash, one->path, &st, 0))
|
||||
die("cannot hash %s", one->path);
|
||||
}
|
||||
}
|
||||
else
|
||||
hashclr(one->sha1);
|
||||
oidclr(&one->oid);
|
||||
}
|
||||
|
||||
static void strip_prefix(int prefix_length, const char **namep, const char **otherp)
|
||||
|
@ -3984,6 +3987,8 @@ int diff_opt_parse(struct diff_options *options,
|
|||
if (!options->file)
|
||||
die_errno("Could not open '%s'", path);
|
||||
options->close_file = 1;
|
||||
if (options->use_color != GIT_COLOR_ALWAYS)
|
||||
options->use_color = GIT_COLOR_NEVER;
|
||||
return argcount;
|
||||
} else
|
||||
return 0;
|
||||
|
@ -4125,8 +4130,9 @@ static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt)
|
|||
fprintf(opt->file, "%s", diff_line_prefix(opt));
|
||||
if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) {
|
||||
fprintf(opt->file, ":%06o %06o %s ", p->one->mode, p->two->mode,
|
||||
diff_unique_abbrev(p->one->sha1, opt->abbrev));
|
||||
fprintf(opt->file, "%s ", diff_unique_abbrev(p->two->sha1, opt->abbrev));
|
||||
diff_unique_abbrev(p->one->oid.hash, opt->abbrev));
|
||||
fprintf(opt->file, "%s ",
|
||||
diff_unique_abbrev(p->two->oid.hash, opt->abbrev));
|
||||
}
|
||||
if (p->score) {
|
||||
fprintf(opt->file, "%c%03d%c", p->status, similarity_index(p),
|
||||
|
@ -4175,11 +4181,11 @@ int diff_unmodified_pair(struct diff_filepair *p)
|
|||
/* both are valid and point at the same path. that is, we are
|
||||
* dealing with a change.
|
||||
*/
|
||||
if (one->sha1_valid && two->sha1_valid &&
|
||||
!hashcmp(one->sha1, two->sha1) &&
|
||||
if (one->oid_valid && two->oid_valid &&
|
||||
!oidcmp(&one->oid, &two->oid) &&
|
||||
!one->dirty_submodule && !two->dirty_submodule)
|
||||
return 1; /* no change */
|
||||
if (!one->sha1_valid && !two->sha1_valid)
|
||||
if (!one->oid_valid && !two->oid_valid)
|
||||
return 1; /* both look at the same file on the filesystem. */
|
||||
return 0;
|
||||
}
|
||||
|
@ -4240,7 +4246,7 @@ void diff_debug_filespec(struct diff_filespec *s, int x, const char *one)
|
|||
s->path,
|
||||
DIFF_FILE_VALID(s) ? "valid" : "invalid",
|
||||
s->mode,
|
||||
s->sha1_valid ? sha1_to_hex(s->sha1) : "");
|
||||
s->oid_valid ? oid_to_hex(&s->oid) : "");
|
||||
fprintf(stderr, "queue[%d] %s size %lu\n",
|
||||
x, one ? one : "",
|
||||
s->size);
|
||||
|
@ -4310,11 +4316,11 @@ static void diff_resolve_rename_copy(void)
|
|||
else
|
||||
p->status = DIFF_STATUS_RENAMED;
|
||||
}
|
||||
else if (hashcmp(p->one->sha1, p->two->sha1) ||
|
||||
else if (oidcmp(&p->one->oid, &p->two->oid) ||
|
||||
p->one->mode != p->two->mode ||
|
||||
p->one->dirty_submodule ||
|
||||
p->two->dirty_submodule ||
|
||||
is_null_sha1(p->one->sha1))
|
||||
is_null_oid(&p->one->oid))
|
||||
p->status = DIFF_STATUS_MODIFIED;
|
||||
else {
|
||||
/* This is a "no-change" entry and should not
|
||||
|
@ -4456,7 +4462,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
|
|||
}
|
||||
|
||||
/* returns 0 upon success, and writes result into sha1 */
|
||||
static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only)
|
||||
{
|
||||
struct diff_queue_struct *q = &diff_queued_diff;
|
||||
int i;
|
||||
|
@ -4491,9 +4497,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
|||
|
||||
diff_fill_sha1_info(p->one);
|
||||
diff_fill_sha1_info(p->two);
|
||||
if (fill_mmfile(&mf1, p->one) < 0 ||
|
||||
fill_mmfile(&mf2, p->two) < 0)
|
||||
return error("unable to read files to diff");
|
||||
|
||||
len1 = remove_space(p->one->path, strlen(p->one->path));
|
||||
len2 = remove_space(p->two->path, strlen(p->two->path));
|
||||
|
@ -4528,10 +4531,19 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
|||
len2, p->two->path);
|
||||
git_SHA1_Update(&ctx, buffer, len1);
|
||||
|
||||
if (diff_header_only)
|
||||
continue;
|
||||
|
||||
if (fill_mmfile(&mf1, p->one) < 0 ||
|
||||
fill_mmfile(&mf2, p->two) < 0)
|
||||
return error("unable to read files to diff");
|
||||
|
||||
if (diff_filespec_is_binary(p->one) ||
|
||||
diff_filespec_is_binary(p->two)) {
|
||||
git_SHA1_Update(&ctx, sha1_to_hex(p->one->sha1), 40);
|
||||
git_SHA1_Update(&ctx, sha1_to_hex(p->two->sha1), 40);
|
||||
git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid),
|
||||
40);
|
||||
git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid),
|
||||
40);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4548,11 +4560,11 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only)
|
||||
{
|
||||
struct diff_queue_struct *q = &diff_queued_diff;
|
||||
int i;
|
||||
int result = diff_get_patch_id(options, sha1);
|
||||
int result = diff_get_patch_id(options, sha1, diff_header_only);
|
||||
|
||||
for (i = 0; i < q->nr; i++)
|
||||
diff_free_filepair(q->queue[i]);
|
||||
|
@ -4823,7 +4835,7 @@ static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
|
|||
*/
|
||||
if (!DIFF_FILE_VALID(p->one) || /* (1) */
|
||||
!DIFF_FILE_VALID(p->two) ||
|
||||
(p->one->sha1_valid && p->two->sha1_valid) ||
|
||||
(p->one->oid_valid && p->two->oid_valid) ||
|
||||
(p->one->mode != p->two->mode) ||
|
||||
diff_populate_filespec(p->one, CHECK_SIZE_ONLY) ||
|
||||
diff_populate_filespec(p->two, CHECK_SIZE_ONLY) ||
|
||||
|
@ -5119,8 +5131,9 @@ size_t fill_textconv(struct userdiff_driver *driver,
|
|||
if (!driver->textconv)
|
||||
die("BUG: fill_textconv called with non-textconv driver");
|
||||
|
||||
if (driver->textconv_cache && df->sha1_valid) {
|
||||
*outbuf = notes_cache_get(driver->textconv_cache, df->sha1,
|
||||
if (driver->textconv_cache && df->oid_valid) {
|
||||
*outbuf = notes_cache_get(driver->textconv_cache,
|
||||
df->oid.hash,
|
||||
&size);
|
||||
if (*outbuf)
|
||||
return size;
|
||||
|
@ -5130,9 +5143,9 @@ size_t fill_textconv(struct userdiff_driver *driver,
|
|||
if (!*outbuf)
|
||||
die("unable to read files to diff");
|
||||
|
||||
if (driver->textconv_cache && df->sha1_valid) {
|
||||
if (driver->textconv_cache && df->oid_valid) {
|
||||
/* ignore errors, as we might be in a readonly repository */
|
||||
notes_cache_put(driver->textconv_cache, df->sha1, *outbuf,
|
||||
notes_cache_put(driver->textconv_cache, df->oid.hash, *outbuf,
|
||||
size);
|
||||
/*
|
||||
* we could save up changes and flush them all at the end,
|
||||
|
|
2
diff.h
2
diff.h
|
@ -342,7 +342,7 @@ extern int run_diff_files(struct rev_info *revs, unsigned int option);
|
|||
extern int run_diff_index(struct rev_info *revs, int cached);
|
||||
|
||||
extern int do_diff_cache(const unsigned char *, struct diff_options *);
|
||||
extern int diff_flush_patch_id(struct diff_options *, unsigned char *);
|
||||
extern int diff_flush_patch_id(struct diff_options *, unsigned char *, int);
|
||||
|
||||
extern int diff_result_code(struct diff_options *, int);
|
||||
|
||||
|
|
|
@ -57,8 +57,8 @@ static int should_break(struct diff_filespec *src,
|
|||
return 1; /* even their types are different */
|
||||
}
|
||||
|
||||
if (src->sha1_valid && dst->sha1_valid &&
|
||||
!hashcmp(src->sha1, dst->sha1))
|
||||
if (src->oid_valid && dst->oid_valid &&
|
||||
!oidcmp(&src->oid, &dst->oid))
|
||||
return 0; /* they are the same */
|
||||
|
||||
if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
|
||||
|
|
|
@ -60,7 +60,8 @@ static int add_rename_dst(struct diff_filespec *two)
|
|||
memmove(rename_dst + first + 1, rename_dst + first,
|
||||
(rename_dst_nr - first - 1) * sizeof(*rename_dst));
|
||||
rename_dst[first].two = alloc_filespec(two->path);
|
||||
fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode);
|
||||
fill_filespec(rename_dst[first].two, two->oid.hash, two->oid_valid,
|
||||
two->mode);
|
||||
rename_dst[first].pair = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -260,12 +261,13 @@ struct file_similarity {
|
|||
|
||||
static unsigned int hash_filespec(struct diff_filespec *filespec)
|
||||
{
|
||||
if (!filespec->sha1_valid) {
|
||||
if (!filespec->oid_valid) {
|
||||
if (diff_populate_filespec(filespec, 0))
|
||||
return 0;
|
||||
hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1);
|
||||
hash_sha1_file(filespec->data, filespec->size, "blob",
|
||||
filespec->oid.hash);
|
||||
}
|
||||
return sha1hash(filespec->sha1);
|
||||
return sha1hash(filespec->oid.hash);
|
||||
}
|
||||
|
||||
static int find_identical_files(struct hashmap *srcs,
|
||||
|
@ -287,7 +289,7 @@ static int find_identical_files(struct hashmap *srcs,
|
|||
struct diff_filespec *source = p->filespec;
|
||||
|
||||
/* False hash collision? */
|
||||
if (hashcmp(source->sha1, target->sha1))
|
||||
if (oidcmp(&source->oid, &target->oid))
|
||||
continue;
|
||||
/* Non-regular files? If so, the modes must match! */
|
||||
if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
|
||||
|
@ -466,7 +468,7 @@ void diffcore_rename(struct diff_options *options)
|
|||
strcmp(options->single_follow, p->two->path))
|
||||
continue; /* not interested */
|
||||
else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
|
||||
is_empty_blob_sha1(p->two->sha1))
|
||||
is_empty_blob_sha1(p->two->oid.hash))
|
||||
continue;
|
||||
else if (add_rename_dst(p->two) < 0) {
|
||||
warning("skipping rename detection, detected"
|
||||
|
@ -476,7 +478,7 @@ void diffcore_rename(struct diff_options *options)
|
|||
}
|
||||
}
|
||||
else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
|
||||
is_empty_blob_sha1(p->one->sha1))
|
||||
is_empty_blob_sha1(p->one->oid.hash))
|
||||
continue;
|
||||
else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) {
|
||||
/*
|
||||
|
@ -539,7 +541,7 @@ void diffcore_rename(struct diff_options *options)
|
|||
rename_dst_nr * rename_src_nr, 50, 1);
|
||||
}
|
||||
|
||||
mx = xcalloc(st_mult(num_create, NUM_CANDIDATE_PER_DST), sizeof(*mx));
|
||||
mx = xcalloc(st_mult(NUM_CANDIDATE_PER_DST, num_create), sizeof(*mx));
|
||||
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
|
||||
struct diff_filespec *two = rename_dst[i].two;
|
||||
struct diff_score *m;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
struct userdiff_driver;
|
||||
|
||||
struct diff_filespec {
|
||||
unsigned char sha1[20];
|
||||
struct object_id oid;
|
||||
char *path;
|
||||
void *data;
|
||||
void *cnt_data;
|
||||
|
@ -33,7 +33,7 @@ struct diff_filespec {
|
|||
int count; /* Reference count */
|
||||
int rename_used; /* Count of rename users */
|
||||
unsigned short mode; /* file mode */
|
||||
unsigned sha1_valid : 1; /* if true, use sha1 and trust mode;
|
||||
unsigned oid_valid : 1; /* if true, use oid and trust mode;
|
||||
* if false, use the name and read from
|
||||
* the filesystem.
|
||||
*/
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче