Merge commit 'mingw/master' into work/merge-mingw

Conflicts:

	help.c
This commit is contained in:
Steffen Prohaska
2007-12-21 08:10:19 +01:00
112 changed files with 2180 additions and 1044 deletions

2
.gitignore vendored
View File

@@ -12,7 +12,6 @@ git-archive
git-bisect
git-blame
git-branch
git-browse-help
git-bundle
git-cat-file
git-check-attr
@@ -52,6 +51,7 @@ git-gc
git-get-tar-commit-id
git-grep
git-hash-object
git-help--browse
git-http-fetch
git-http-push
git-imap-send

View File

@@ -25,6 +25,7 @@ Karl Hasselström <kha@treskal.com>
Kent Engstrom <kent@lysator.liu.se>
Lars Doelle <lars.doelle@on-line ! de>
Lars Doelle <lars.doelle@on-line.de>
Li Hong <leehong@pku.edu.cn>
Lukas Sandström <lukass@etek.chalmers.se>
Martin Langhoff <martin@catalyst.net.nz>
Michael Coleman <tutufan@gmail.com>

View File

@@ -2,6 +2,7 @@
*.html
*.[1-8]
*.made
git.info
howto-index.txt
doc.dep
cmds-*.txt

View File

@@ -24,6 +24,9 @@ ARTICLES += git-tools
ARTICLES += glossary
# with their own formatting rules.
SP_ARTICLES = howto/revert-branch-rebase user-manual
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
SP_ARTICLES += $(API_DOCS)
SP_ARTICLES += technical/api-index
DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
@@ -142,10 +145,12 @@ cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
git.7 git.html: git.txt
clean:
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 *.texi *.texi+ howto-index.txt howto/*.html doc.dep
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 *.texi *.texi+ git.info
$(RM) howto-index.txt howto/*.html doc.dep
$(RM) technical/api-*.html technical/api-index.txt
$(RM) $(cmds_txt) *.made
%.html : %.txt
$(MAN_HTML): %.html : %.txt
$(RM) $@+ $@
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
@@ -164,6 +169,14 @@ clean:
user-manual.xml: user-manual.txt user-manual.conf
$(ASCIIDOC) -b docbook -d book $<
technical/api-index.txt: technical/api-index-skel.txt \
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
cd technical && sh ./api-index.sh
$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt
$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt
XSLT = docbook.xsl
XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css

View File

@@ -7,15 +7,17 @@ Removal
* "git svnimport" was removed in favor of "git svn". It is still there
in the source tree (contrib/examples) but unsupported.
* As git-commit and git-status have been rewritten, "git runstatus"
helper script lost all its users and has been removed.
Deprecation notices
-------------------
* Next feature release of git (this change is scheduled for v1.5.5 but
it could slip) will by default install dashed form of commands
(e.g. "git-commit") outside of users' normal $PATH, and will install
only selected commands ("git" itself, and "gitk") in $PATH. This
implies:
* Next feature release of git (this change is scheduled for v1.6.0)
will by default install dashed form of commands (e.g. "git-commit")
outside of users' normal $PATH, and will install only selected
commands ("git" itself, and "gitk") in $PATH. This implies:
- Using dashed form of git commands (e.g. "git-commit") from the
command line has been informally deprecated since early 2006, but
@@ -35,7 +37,7 @@ Deprecation notices
* The post-receive hook was introduced in March 2007 to supersede
post-update hook, primarily to overcome the command line length
limitation of the latter. Use of post-update hook will be deprecated
in future versions of git, perhaps in v1.5.5.
in future versions of git, starting from v1.6.0.
* "git lost-found" was deprecated in favor of "git fsck"'s --lost-found
option, and will be removed in the future.
@@ -43,6 +45,17 @@ Deprecation notices
* "git peek-remote" is deprecated, as "git ls-remote" was written in C
and works for all transports, and will be removed in the future.
* From v1.6.0, the repack.usedeltabaseoffset config option will default
to true, which will give denser packfile (i.e. more efficient storage).
The downside is that git older than version 1.4.4 will not be able
to directly use a repository packed using this setting.
* From v1.6.0, the pack.indexversion config option will default to 2,
which is slightly more efficient, and makes repacking more immune to
data corruptions. Git older than version 1.5.2 may revert to version 1
of the pack index with a manual "git index-pack" to be able to directly
access corresponding pack files.
Updates since v1.5.3
--------------------
@@ -74,6 +87,9 @@ Updates since v1.5.3
mean "always" (even when the output is not going to a terminal).
This has been corrected to mean the same thing as "auto".
* "git diff" Porcelain now respects diff.external configuration, which
is another way to specify GIT_EXTERNAL_DIFF.
* HTTP proxy can be specified per remote repository using
remote.*.httpproxy configuration, or global http.proxy configuration
variable.
@@ -98,6 +114,8 @@ Updates since v1.5.3
* "git rebase --interactive" mode can now work on detached HEAD.
* Other minor to serious bugs in "git rebase -i" has been fixed.
* "git rebase" now detaches head during its operation, so after a
successful "git rebase" operation, the reflog entry branch@{1} for
the current branch points at the commit before the rebase was
@@ -224,6 +242,12 @@ Updates since v1.5.3
"git commit"; the parameters to -m options are formatted as separate
paragraphs.
* The format "git show" outputs an annotated tag has been updated to
include "Tagger: " and "Date: " lines from the tag itself. Strictly
speaking this is a backward incompatible change, but this is a
reasonable usability fix and people's script shouldn't have been
relying on the exact output from "git show" Porcelain anyway.
* "git cvsexportcommit" learned -w option to specify and switch to the
CVS working directory.
@@ -250,6 +274,9 @@ Updates since v1.5.3
between svn and git; a new representation that is much more compact
for this information has been introduced to correct this.
* "git svn" left temporary index files it used without cleaning them
up; this was corrected.
* "git status" from a subdirectory now shows relative paths, which
makes copy-and-pasting for git-checkout/git-add/git-rm easier. The
traditional behaviour to show the full path relative to the top of
@@ -286,6 +313,9 @@ this release, unless otherwise noted.
These fixes are only in v1.5.4 and not backported to v1.5.3 maintenance
series.
* The way "git diff --check" behaves is much more consistent with the way
"git apply --whitespace=warn" works.
* "git svn" talking with the SVN over http will correctly quote branch
and project names.
@@ -294,6 +324,6 @@ series.
--
exec >/var/tmp/1
O=v1.5.4-rc0
O=v1.5.4-rc0-85-gdbedf97
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint

View File

@@ -307,7 +307,7 @@ core.whitespace::
before a tab character in the initial indent part of the line as an
error (enabled by default).
* `indent-with-non-tab` treats a line that is indented with 8 or more
space characters that can be replaced with tab characters.
space characters as an error (not enabled by default).
alias.*::
Command aliases for the gitlink:git[1] command wrapper - e.g.
@@ -448,6 +448,13 @@ diff.autorefreshindex::
affects only `git diff` Porcelain, and not lower level
`diff` commands, such as `git diff-files`.
diff.external::
If this config variable is set, diff generation is not
performed using the internal diff machinery, but using the
given command. Note: if you want to use an external diff
program only on a subset of your files, you might want to
use gitlink:gitattributes[5] instead.
diff.renameLimit::
The number of files to consider when performing the copy/rename
detection; equivalent to the git diff option '-l'.
@@ -469,7 +476,7 @@ fetch.unpackLimit::
format.numbered::
A boolean which can enable sequence numbers in patch subjects.
Seting this option to "auto" will enable it only if there is
Setting this option to "auto" will enable it only if there is
more than one patch. See --numbered option in
gitlink:git-format-patch[1].
@@ -671,6 +678,10 @@ merge.<driver>.recursive::
performing an internal merge between common ancestors.
See gitlink:gitattributes[5] for details.
mergetool.<tool>.path::
Override the path for the given tool. This is useful in case
your tool is not in the PATH.
pack.window::
The size of the window used by gitlink:git-pack-objects[1] when no
window size is given on the command line. Defaults to 10.

View File

@@ -93,7 +93,9 @@ endif::git-format-patch[]
--check::
Warn if changes introduce trailing whitespace
or an indent that uses a space before a tab.
or an indent that uses a space before a tab. Exits with
non-zero status if problems are found. Not compatible with
--exit-code.
--full-index::
Instead of the first handful characters, show full

View File

@@ -31,8 +31,8 @@ pass some directory paths as 'git-daemon' arguments, you can further restrict
the offers to a whitelist comprising of those.
By default, only `upload-pack` service is enabled, which serves
`git-fetch-pack` and `git-peek-remote` clients that are invoked
from `git-fetch`, `git-ls-remote`, and `git-clone`.
`git-fetch-pack` and `git-ls-remote` clients, which are invoked
from `git-fetch`, `git-pull`, and `git-clone`.
This is ideally suited for read-only updates, i.e., pulling from
git repositories.
@@ -166,7 +166,7 @@ the per-repository configuration file can be used to enable or
disable them.
upload-pack::
This serves `git-fetch-pack` and `git-peek-remote`
This serves `git-fetch-pack` and `git-ls-remote`
clients. It is enabled by default, but a repository can
disable it by setting `daemon.uploadpack` configuration
item to `false`.

View File

@@ -7,7 +7,7 @@ git-help - display help information about git
SYNOPSIS
--------
'git help' [-a|--all|-i|--info|-w|--web] [COMMAND]
'git help' [-a|--all|-i|--info|-m|--man|-w|--web] [COMMAND]
DESCRIPTION
-----------
@@ -21,7 +21,7 @@ printed on the standard output.
If a git command is named, a manual page for that command is brought
up. The 'man' program is used by default for this purpose, but this
can be overriden by other options.
can be overridden by other options or configuration variables.
Note that 'git --help ...' is identical as 'git help ...' because the
former is internally converted into the latter.
@@ -30,30 +30,63 @@ OPTIONS
-------
-a|--all::
Prints all the available commands on the standard output. This
option superseeds any other option.
option supersedes any other option.
-i|--info::
Use the 'info' program to display the manual page, instead of
the 'man' program that is used by default.
-m|--man::
Use the 'man' program to display the manual page. This may be
used to override a value set in the 'help.format'
configuration variable.
-w|--web::
Use a web browser to display the HTML manual page, instead of
the 'man' program that is used by default.
+
The web browser can be specified using the configuration variable
'help.browser', or 'web.browser' if the former is not set. If none of
these config variables is set, the 'git-browse-help' script (called by
'git-help') will pick a suitable default.
these config variables is set, the 'git-help--browse' helper script
(called by 'git-help') will pick a suitable default.
+
You can explicitly provide a full path to your prefered browser by
You can explicitly provide a full path to your preferred browser by
setting the configuration variable 'browser.<tool>.path'. For example,
you can configure the absolute path to firefox by setting
'browser.firefox.path'. Otherwise, 'git-browse-help' assumes the tool
'browser.firefox.path'. Otherwise, 'git-help--browse' assumes the tool
is available in PATH.
+
Note that the script tries, as much as possible, to display the HTML
page in a new tab on an already opened browser.
CONFIGURATION VARIABLES
-----------------------
If no command line option is passed, the 'help.format' configuration
variable will be checked. The following values are supported for this
variable; they make 'git-help' behave as their corresponding command
line option:
* "man" corresponds to '-m|--man',
* "info" corresponds to '-i|--info',
* "web" or "html" correspond to '-w|--web',
The 'help.browser', 'web.browser' and 'browser.<tool>.path' will also
be checked if the 'web' format is chosen (either by command line
option or configuration variable). See '-w|--web' in the OPTIONS
section above.
Note that these configuration variables should probably be set using
the '--global' flag, for example like this:
------------------------------------------------
$ git config --global help.format web
$ git config --global web.browser firefox
------------------------------------------------
as they are probably more user specific than repository specific.
See gitlink:git-config[1] for more information about this.
Author
------
Written by Junio C Hamano <gitster@pobox.com> and the git-list

View File

@@ -52,7 +52,7 @@ is given:
- 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
readable by all users.
By default, the configuration flag receive.denyNonFastforward is enabled
By default, the configuration flag receive.denyNonFastForwards is enabled
in shared repositories, so that you cannot force a non fast-forwarding push
into it.

View File

@@ -30,7 +30,7 @@ OPTIONS
Specify the full path of gitlink:git-upload-pack[1] on the remote
host. This allows listing references from repositories accessed via
SSH and where the SSH daemon does not use the PATH configured by the
user. Also see the '--exec' option for gitlink:git-peek-remote[1].
user.
<repository>::
Location of the repository. The shorthand defined in

View File

@@ -28,9 +28,6 @@ OPTIONS
shells, but prefer having a lean .bashrc file (they set most of
the things up in .bash_profile).
\--exec=<git-upload-pack>::
Same \--upload-pack=<git-upload-pack>.
<host>::
A remote host that houses the repository. When this
part is specified, 'git-upload-pack' is invoked via

View File

@@ -274,7 +274,7 @@ limiting may be applied.
--quiet::
Don't print anything to standard output. This form of
git-rev-list is primarly meant to allow the caller to
git-rev-list is primarily meant to allow the caller to
test the exit status to see if a range of objects is fully
connected (or not). It is faster than redirecting stdout
to /dev/null as the output does not have to be formatted.

View File

@@ -1,68 +0,0 @@
git-runstatus(1)
================
NAME
----
git-runstatus - A helper for git-status and git-commit
SYNOPSIS
--------
'git-runstatus' [--color|--nocolor] [--amend] [--verbose] [--untracked]
DESCRIPTION
-----------
Examines paths in the working tree that has changes unrecorded
to the index file, and changes between the index file and the
current HEAD commit. The former paths are what you _could_
commit by running 'git add' (or 'git rm' if you are deleting) before running 'git
commit', and the latter paths are what you _would_ commit by
running 'git commit'.
If there is no path that is different between the index file and
the current HEAD commit, the command exits with non-zero status.
Note that this is _not_ the user level command you would want to
run from the command line. Use 'git-status' instead.
OPTIONS
-------
--color::
Show colored status, highlighting modified file names.
--nocolor::
Turn off coloring.
--amend::
Show status based on HEAD^1, not HEAD, i.e. show what
'git-commit --amend' would do.
--verbose::
Show unified diff of all file changes.
--untracked::
Show files in untracked directories, too. Without this
option only its name and a trailing slash are displayed
for each untracked directory.
OUTPUT
------
The output from this command is designed to be used as a commit
template comments, and all the output lines are prefixed with '#'.
Author
------
Originally written by Linus Torvalds <torvalds@osdl.org> as part
of git-commit, and later rewritten in C by Jeff King.
Documentation
--------------
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT
---
Part of the gitlink:git[7] suite

View File

@@ -148,7 +148,7 @@ sendemail.identity::
'sendemail.<identity>.<item>' will have higher precedence than
'sendemail.<item>'. This is useful to declare multiple SMTP
identities and to hoist sensitive authentication information
out of the repository and into the global configuation file.
out of the repository and into the global configuration file.
sendemail.aliasesfile::
To avoid typing long email addresses, point this to one or more

View File

@@ -160,7 +160,7 @@ to get a listing of all tags together with what they dereference.
SEE ALSO
--------
gitlink:git-ls-remote[1], gitlink:git-peek-remote[1]
gitlink:git-ls-remote[1]
AUTHORS
-------

View File

@@ -68,7 +68,8 @@ FILES
When initializing submodules, a .gitmodules file in the top-level directory
of the containing repository is used to find the url of each submodule.
This file should be formatted in the same way as $GIR_DIR/config. The key
to each submodule url is "submodule.$name.url".
to each submodule url is "submodule.$name.url". See gitlink:gitmodules[5]
for details.
AUTHOR

View File

@@ -153,6 +153,8 @@ introductions to the underlying git architecture.
See also the link:howto-index.html[howto] documents for some useful
examples.
The internals are documented link:technical/api-index.html[here].
GIT COMMANDS
------------
@@ -500,7 +502,7 @@ as tags and branch heads.
The object database contains objects of three main types: blobs, which
hold file data; trees, which point to blobs and other trees to build up
directory heirarchies; and commits, which each reference a single tree
directory hierarchies; and commits, which each reference a single tree
and some number of parent commits.
The commit, equivalent to what other systems call a "changeset" or
@@ -520,7 +522,7 @@ efficiency may later be compressed together into "pack files".
Named pointers called refs mark interesting points in history. A ref
may contain the SHA1 name of an object or the name of another ref. Refs
with names beginning `ref/head/` contain the SHA1 name of the most
recent commit (or "head") of a branch under developement. SHA1 names of
recent commit (or "head") of a branch under development. SHA1 names of
tags of interest are stored under `ref/tags/`. A special ref named
`HEAD` contains the name of the currently checked-out branch.

View File

@@ -2,9 +2,16 @@
T="$1"
for h in *.html *.txt howto/*.txt howto/*.html RelNotes-*.txt *.css
for h in \
*.txt *.html \
howto/*.txt howto/*.html \
technical/*.txt technical/*.html \
RelNotes-*.txt *.css
do
if test -f "$T/$h" &&
if test ! -f "$h"
then
: did not match
elif test -f "$T/$h" &&
diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h"
then
:; # up to date
@@ -16,7 +23,10 @@ do
fi
done
strip_leading=`echo "$T/" | sed -e 's|.|.|g'`
for th in "$T"/*.html "$T"/*.txt "$T"/howto/*.txt "$T"/howto/*.html
for th in \
"$T"/*.html "$T"/*.txt \
"$T"/howto/*.txt "$T"/howto/*.html \
"$T"/technical/*.txt "$T"/technical/*.html
do
h=`expr "$th" : "$strip_leading"'\(.*\)'`
case "$h" in

1
Documentation/technical/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
api-index.txt

View File

@@ -0,0 +1,34 @@
allocation growing API
======================
Dynamically growing an array using realloc() is error prone and boring.
Define your array with:
* a pointer (`ary`) that points at the array, initialized to `NULL`;
* an integer variable (`alloc`) that keeps track of how big the current
allocation is, initialized to `0`;
* another integer variable (`nr`) to keep track of how many elements the
array currently has, initialized to `0`.
Then before adding `n`th element to the array, call `ALLOC_GROW(ary, n,
alloc)`. This ensures that the array can hold at least `n` elements by
calling `realloc(3)` and adjusting `alloc` variable.
------------
sometype *ary;
size_t nr;
size_t alloc
for (i = 0; i < nr; i++)
if (we like ary[i] already)
return;
/* we did not like any existing one, so add one */
ALLOC_GROW(ary, nr + 1, alloc);
ary[nr++] = value you like;
------------
You are responsible for updating the `nr` variable.

View File

@@ -0,0 +1,63 @@
builtin API
===========
Adding a new built-in
---------------------
There are 4 things to do to add a bulit-in command implementation to
git:
. Define the implementation of the built-in command `foo` with
signature:
int cmd_foo(int argc, const char **argv, const char *prefix);
. Add the external declaration for the function to `builtin.h`.
. Add the command to `commands[]` table in `handle_internal_command()`,
defined in `git.c`. The entry should look like:
{ "foo", cmd_foo, <options> },
where options is the bitwise-or of:
`RUN_SETUP`::
Make sure there is a git directory to work on, and if there is a
work tree, chdir to the top of it if the command was invoked
in a subdirectory. If there is no work tree, no chdir() is
done.
`USE_PAGER`::
If the standard output is connected to a tty, spawn a pager and
feed our output to it.
. Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`.
Additionally, if `foo` is a new command, there are 3 more things to do:
. Add tests to `t/` directory.
. Write documentation in `Documentation/git-foo.txt`.
. Add an entry for `git-foo` to the list at the end of
`Documentation/cmd-list.perl`.
How a built-in is called
------------------------
The implementation `cmd_foo()` takes three parameters, `argc`, `argv,
and `prefix`. The first two are similar to what `main()` of a
standalone command would be called with.
When `RUN_SETUP` is specified in the `commands[]` table, and when you
were started from a subdirectory of the work tree, `cmd_foo()` is called
after chdir(2) to the top of the work tree, and `prefix` gets the path
to the subdirectory the command started from. This allows you to
convert a user-supplied pathname (typically relative to that directory)
to a pathname relative to the top of the work tree.
The return value from `cmd_foo()` becomes the exit status of the
command.

View File

@@ -0,0 +1,6 @@
decorate API
============
Talk about <decorate.h>
(Linus)

View File

@@ -0,0 +1,166 @@
diff API
========
The diff API is for programs that compare two sets of files (e.g. two
trees, one tree and the index) and present the found difference in
various ways. The calling program is responsible for feeding the API
pairs of files, one from the "old" set and the corresponding one from
"new" set, that are different. The library called through this API is
called diffcore, and is responsible for two things.
* finding total rewrites (`-B`), renames (`-M`) and copies (`-C`), and
changes that touch a string (`-S`), as specified by the caller.
* outputting the differences in various formats, as specified by the
caller.
Calling sequence
----------------
* Prepare `struct diff_options` to record the set of diff options, and
then call `diff_setup()` to initialize this structure. This sets up
the vanilla default.
* Fill in the options structure to specify desired output format, rename
detection, etc. `diff_opt_parse()` can be used to parse options given
from the command line in a way consistent with existing git-diff
family of programs.
* Call `diff_setup_done()`; this inspects the options set up so far for
internal consistency and make necessary tweaking to it (e.g. if
textual patch output was asked, recursive behaviour is turned on).
* As you find different pairs of files, call `diff_change()` to feed
modified files, `diff_addremove()` to feed created or deleted files,
or `diff_unmerged()` to feed a file whose state is 'unmerged' to the
API. These are thin wrappers to a lower-level `diff_queue()` function
that is flexible enough to record any of these kinds of changes.
* Once you finish feeding the pairs of files, call `diffcore_std()`.
This will tell the diffcore library to go ahead and do its work.
* Calling `diffcore_flush()` will produce the output.
Data structures
---------------
* `struct diff_filespec`
This is the internal representation for a single file (blob). It
records the blob object name (if known -- for a work tree file it
typically is a NUL SHA-1), filemode and pathname. This is what the
`diff_addremove()`, `diff_change()` and `diff_unmerged()` synthesize and
feed `diff_queue()` function with.
* `struct diff_filepair`
This records a pair of `struct diff_filespec`; the filespec for a file
in the "old" set (i.e. preimage) is called `one`, and the filespec for a
file in the "new" set (i.e. postimage) is called `two`. A change that
represents file creation has NULL in `one`, and file deletion has NULL
in `two`.
A `filepair` starts pointing at `one` and `two` that are from the same
filename, but `diffcore_std()` can break pairs and match component
filespecs with other filespecs from a different filepair to form new
filepair. This is called 'rename detection'.
* `struct diff_queue`
This is a collection of filepairs. Notable members are:
`queue`::
An array of pointers to `struct diff_filepair`. This
dynamically grows as you add filepairs;
`alloc`::
The allocated size of the `queue` array;
`nr`::
The number of elements in the `queue` array.
* `struct diff_options`
This describes the set of options the calling program wants to affect
the operation of diffcore library with.
Notable members are:
`output_format`::
The output format used when `diff_flush()` is run.
`context`::
Number of context lines to generate in patch output.
`break_opt`, `detect_rename`, `rename-score`, `rename_limit`::
Affects the way detection logic for complete rewrites, renames
and copies.
`abbrev`::
Number of hexdigits to abbrevate raw format output to.
`pickaxe`::
A constant string (can and typically does contain newlines to
look for a block of text, not just a single line) to filter out
the filepairs that do not change the number of strings contained
in its preimage and postmage of the diff_queue.
`flags`::
This is mostly a collection of boolean options that affects the
operation, but some do not have anything to do with the diffcore
library.
BINARY, TEXT;;
Affects the way how a file that is seemingly binary is treated.
FULL_INDEX;;
Tells the patch output format not to use abbreviated object
names on the "index" lines.
FIND_COPIES_HARDER;;
Tells the diffcore library that the caller is feeding unchanged
filepairs to allow copies from unmodified files be detected.
COLOR_DIFF;;
Output should be colored.
COLOR_DIFF_WORDS;;
Output is a colored word-diff.
NO_INDEX;;
Tells diff-files that the input is not tracked files but files
in random locations on the filesystem.
ALLOW_EXTERNAL;;
Tells output routine that it is Ok to call user specified patch
output routine. Plumbing disables this to ensure stable output.
QUIET;;
Do not show any output.
REVERSE_DIFF;;
Tells the library that the calling program is feeding the
filepairs reversed; `one` is two, and `two` is one.
EXIT_WITH_STATUS;;
For communication between the calling program and the options
parser; tell the calling program to signal the presense of
difference using program exit code.
HAS_CHANGES;;
Internal; used for optimization to see if there is any change.
SILENT_ON_REMOVE;;
Affects if diff-files shows removed files.
RECURSIVE, TREE_IN_RECURSIVE;;
Tells if tree traversal done by tree-diff should recursively
descend into a tree object pair that are different in preimage
and postimage set.
(JC)

View File

@@ -0,0 +1,76 @@
directory listing API
=====================
The directory listing API is used to enumerate paths in the work tree,
optionally taking `.git/info/exclude` and `.gitignore` files per
directory into account.
Data structure
--------------
`struct dir_struct` structure is used to pass directory traversal
options to the library and to record the paths discovered. The notable
options are:
`exclude_per_dir`::
The name of the file to be read in each directory for excluded
files (typically `.gitignore`).
`collect_ignored`::
Include paths that are to be excluded in the result.
`show_ignored`::
The traversal is for finding just ignored files, not unignored
files.
`show_other_directories`::
Include a directory that is not tracked.
`hide_empty_directories`::
Do not include a directory that is not tracked and is empty.
`no_gitlinks`::
If set, recurse into a directory that looks like a git
directory. Otherwise it is shown as a directory.
The result of the enumeration is left in these fields::
`entries[]`::
An array of `struct dir_entry`, each element of which describes
a path.
`nr`::
The number of members in `entries[]` array.
`alloc`::
Internal use; keeps track of allocation of `entries[]` array.
Calling sequence
----------------
* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
sizeof(dir))`.
* Call `add_exclude()` to add single exclude pattern,
`add_excludes_from_file()` to add patterns from a file
(e.g. `.git/info/exclude`), and/or set `dir.exclude_per_dir`. A
short-hand function `setup_standard_excludes()` can be used to set up
the standard set of exclude settings.
* Set options described in the Data Structure section above.
* Call `read_directory()`.
* Use `dir.entries[]`.
(JC)

View File

@@ -0,0 +1,111 @@
gitattributes API
=================
gitattributes mechanism gives a uniform way to associate various
attributes to set of paths.
Data Structure
--------------
`struct git_attr`::
An attribute is an opaque object that is identified by its name.
Pass the name and its length to `git_attr()` function to obtain
the object of this type. The internal representation of this
structure is of no interest to the calling programs.
`struct git_attr_check`::
This structure represents a set of attributes to check in a call
to `git_checkattr()` function, and receives the results.
Calling Sequence
----------------
* Prepare an array of `struct git_attr_check` to define the list of
attributes you would want to check. To populate this array, you would
need to define necessary attributes by calling `git_attr()` function.
* Call git_checkattr() to check the attributes for the path.
* Inspect `git_attr_check` structure to see how each of the attribute in
the array is defined for the path.
Attribute Values
----------------
An attribute for a path can be in one of four states: Set, Unset,
Unspecified or set to a string, and `.value` member of `struct
git_attr_check` records it. There are three macros to check these:
`ATTR_TRUE()`::
Returns true if the attribute is Set for the path.
`ATTR_FALSE()`::
Returns true if the attribute is Unset for the path.
`ATTR_UNSET()`::
Returns true if the attribute is Unspecified for the path.
If none of the above returns true, `.value` member points at a string
value of the attribute for the path.
Example
-------
To see how attributes "crlf" and "indent" are set for different paths.
. Prepare an array of `struct git_attr_check` with two elements (because
we are checking two attributes). Initialize their `attr` member with
pointers to `struct git_attr` obtained by calling `git_attr()`:
------------
static struct git_attr_check check[2];
static void setup_check(void)
{
if (check[0].attr)
return; /* already done */
check[0].attr = git_attr("crlf", 4);
check[1].attr = git_attr("ident", 5);
}
------------
. Call `git_checkattr()` with the prepared array of `struct git_attr_check`:
------------
const char *path;
setup_check();
git_checkattr(path, ARRAY_SIZE(check), check);
------------
. Act on `.value` member of the result, left in `check[]`:
------------
const char *value = check[0].value;
if (ATTR_TRUE(value)) {
The attribute is Set, by listing only the name of the
attribute in the gitattributes file for the path.
} else if (ATTR_FALSE(value)) {
The attribute is Unset, by listing the name of the
attribute prefixed with a dash - for the path.
} else if (ATTR_UNSET(value)) {
The attribute is not set nor unset for the path.
} else if (!strcmp(value, "input")) {
If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is
true, the value is a string set in the gitattributes
file for the path by saying "attr=value".
} else if (... other check using value as string ...) {
...
}
------------
(JC)

View File

@@ -0,0 +1,8 @@
grep API
========
Talk about <grep.h>, things like:
* grep_buffer()
(JC)

View File

@@ -0,0 +1,6 @@
hash API
========
Talk about <hash.h>
(Linus)

View File

@@ -0,0 +1,21 @@
in-core index API
=================
Talk about <read-cache.c> and <cache-tree.c>, things like:
* cache -> the_index macros
* read_index()
* write_index()
* ie_match_stat() and ie_modified(); how they are different and when to
use which.
* index_name_pos()
* remove_index_entry_at()
* remove_file_from_index()
* add_file_to_index()
* add_index_entry()
* refresh_index()
* discard_index()
* cache_tree_invalidate_path()
* cache_tree_update()
(JC, Linus)

View File

@@ -0,0 +1,15 @@
GIT API Documents
=================
GIT has grown a set of internal API over time. This collection
documents them.
////////////////////////////////////////////////////////////////
// table of contents begin
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// table of contents end
////////////////////////////////////////////////////////////////
2007-11-24

View File

@@ -0,0 +1,28 @@
#!/bin/sh
(
c=////////////////////////////////////////////////////////////////
skel=api-index-skel.txt
sed -e '/^\/\/ table of contents begin/q' "$skel"
echo "$c"
ls api-*.txt |
while read filename
do
case "$filename" in
api-index-skel.txt | api-index.txt) continue ;;
esac
title=$(sed -e 1q "$filename")
html=${filename%.txt}.html
echo "* link:$html[$title]"
done
echo "$c"
sed -n -e '/^\/\/ table of contents end/,$p' "$skel"
) >api-index.txt+
if test -f api-index.txt && cmp api-index.txt api-index.txt+ >/dev/null
then
rm -f api-index.txt+
else
mv api-index.txt+ api-index.txt
fi

View File

@@ -0,0 +1,12 @@
lockfile API
============
Talk about <lockfile.c>, things like:
* lockfile lifetime -- atexit(3) looks at them, do not put them on the
stack;
* hold_lock_file_for_update()
* commit_lock_file()
* rollback_rock_file()
(JC, Dscho, Shawn)

View File

@@ -0,0 +1,15 @@
object access API
=================
Talk about <sha1_file.c> and <object.h> family, things like
* read_sha1_file()
* read_object_with_reference()
* has_sha1_file()
* write_sha1_file()
* pretend_sha1_file()
* lookup_{object,commit,tag,blob,tree}
* parse_{object,commit,tag,blob,tree}
* Use of object flags
(JC, Shawn, Daniel, Dscho, Linus)

View File

@@ -0,0 +1,6 @@
parse-options API
=================
Talk about <parse-options.h>
(Pierre)

View File

@@ -0,0 +1,9 @@
path-list API
=============
Talk about <path-list.h>, things like
* it is not just paths but strings in general;
* the calling sequence.
(Dscho)

View File

@@ -0,0 +1,10 @@
quote API
=========
Talk about <quote.h>, things like
* sq_quote and unquote
* c_style quote and unquote
* quoting for foreign languages
(JC)

View File

@@ -0,0 +1,9 @@
revision walking API
====================
Talk about <revision.h>, things like:
* two diff_options, one for path limiting, another for output;
* calling sequence: init_revisions(), setup_revsions(), get_revision();
(Linus, JC, Dscho)

View File

@@ -0,0 +1,10 @@
run-command API
===============
Talk about <run-command.h>, and things like:
* Environment the command runs with (e.g. GIT_DIR);
* File descriptors and pipes;
* Exit status;
(Hannes, Dscho, Shawn)

View File

@@ -0,0 +1,13 @@
setup API
=========
Talk about
* setup_git_directory()
* setup_git_directory_gently()
* is_inside_git_dir()
* is_inside_work_tree()
* setup_work_tree()
* get_pathspec()
(Dscho)

View File

@@ -0,0 +1,6 @@
strbuf API
==========
Talk about <strbuf.h>
(Pierre, JC)

View File

@@ -0,0 +1,12 @@
tree walking API
================
Talk about <tree-walk.h>, things like
* struct tree_desc
* init_tree_desc
* tree_entry_extract
* update_tree_entry
* get_tree_entry
(JC, Linus)

View File

@@ -0,0 +1,7 @@
xdiff interface API
===================
Talk about our calling convention to xdiff library, including
xdiff_emit_consume_fn.
(Dscho, JC)

View File

@@ -1,9 +1,9 @@
GIT pack format
===============
= pack-*.pack file has the following format:
= pack-*.pack files have the following format:
- The header appears at the beginning and consists of the following:
- A header appears at the beginning and consists of the following:
4-byte signature:
The signature is: {'P', 'A', 'C', 'K'}
@@ -34,18 +34,14 @@ GIT pack format
- The trailer records 20-byte SHA1 checksum of all of the above.
= pack-*.idx file has the following format:
= Original (version 1) pack-*.idx files have the following format:
- The header consists of 256 4-byte network byte order
integers. N-th entry of this table records the number of
objects in the corresponding pack, the first byte of whose
object name are smaller than N. This is called the
object name is less than or equal to N. This is called the
'first-level fan-out' table.
Observation: we would need to extend this to an array of
8-byte integers to go beyond 4G objects per pack, but it is
not strictly necessary.
- The header is followed by sorted 24-byte entries, one entry
per object in the pack. Each entry is:
@@ -55,10 +51,6 @@ GIT pack format
20-byte object name.
Observation: we would definitely need to extend this to
8-byte integer plus 20-byte object name to handle a packfile
that is larger than 4GB.
- The file is concluded with a trailer:
A copy of the 20-byte SHA1 checksum at the end of
@@ -68,31 +60,30 @@ GIT pack format
Pack Idx file:
idx
+--------------------------------+
| fanout[0] = 2 |-.
+--------------------------------+ |
-- +--------------------------------+
fanout | fanout[0] = 2 (for example) |-.
table +--------------------------------+ |
| fanout[1] | |
+--------------------------------+ |
| fanout[2] | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| fanout[255] | |
+--------------------------------+ |
main | offset | |
index | object name 00XXXXXXXXXXXXXXXX | |
table +--------------------------------+ |
| offset | |
| object name 00XXXXXXXXXXXXXXXX | |
+--------------------------------+ |
.-| offset |<+
| | object name 01XXXXXXXXXXXXXXXX |
| +--------------------------------+
| | offset |
| | object name 01XXXXXXXXXXXXXXXX |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | offset |
| | object name FFXXXXXXXXXXXXXXXX |
| +--------------------------------+
| fanout[255] = total objects |---.
-- +--------------------------------+ | |
main | offset | | |
index | object name 00XXXXXXXXXXXXXXXX | | |
table +--------------------------------+ | |
| offset | | |
| object name 00XXXXXXXXXXXXXXXX | | |
+--------------------------------+<+ |
.-| offset | |
| | object name 01XXXXXXXXXXXXXXXX | |
| +--------------------------------+ |
| | offset | |
| | object name 01XXXXXXXXXXXXXXXX | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | offset | |
| | object name FFXXXXXXXXXXXXXXXX | |
--| +--------------------------------+<--+
trailer | | packfile checksum |
| +--------------------------------+
| | idxfile checksum |
@@ -116,3 +107,40 @@ Pack file entry: <+
20-byte base object name SHA1 (the size above is the
size of the delta data that follows).
delta data, deflated.
= Version 2 pack-*.idx files support packs larger than 4 GiB, and
have some other reorganizations. They have the format:
- A 4-byte magic number '\377tOc' which is an unreasonable
fanout[0] value.
- A 4-byte version number (= 2)
- A 256-entry fan-out table just like v1.
- A table of sorted 20-byte SHA1 object names. These are
packed together without offset values to reduce the cache
footprint of the binary search for a specific object name.
- A table of 4-byte CRC32 values of the packed object data.
This is new in v2 so compressed data can be copied directly
from pack to pack during repacking withough undetected
data corruption.
- A table of 4-byte offset values (in network byte order).
These are usually 31-bit pack file offsets, but large
offsets are encoded as an index into the next table with
the msbit set.
- A table of 8-byte offset entries (empty for pack files less
than 2 GiB). Pack files are organized with heavily used
objects toward the front, so most object references should
not need to refer to this table.
- The same trailer as a v1 pack file:
A copy of the 20-byte SHA1 checksum at the end of
corresponding packfile.
20-byte SHA1-checksum of all of the above.

View File

@@ -1994,7 +1994,7 @@ $ git push ssh://yourserver.com/~you/proj.git +master
-------------------------------------------------
Normally whenever a branch head in a public repository is modified, it
is modified to point to a descendent of the commit that it pointed to
is modified to point to a descendant of the commit that it pointed to
before. By forcing a push in this situation, you break that convention.
(See <<problems-with-rewriting-history>>.)
@@ -2921,7 +2921,7 @@ As you can see, a commit is defined by:
- a tree: The SHA1 name of a tree object (as defined below), representing
the contents of a directory at a certain point in time.
- parent(s): The SHA1 name of some number of commits which represent the
immediately prevoius step(s) in the history of the project. The
immediately previous step(s) in the history of the project. The
example above has one parent; merge commits may have more than
one. A commit with no parents is called a "root" commit, and
represents the initial revision of a project. Each project must have
@@ -3242,7 +3242,7 @@ to replace them by hand. Back up your repository before attempting this
in case you corrupt things even more in the process.
We'll assume that the problem is a single missing or corrupted blob,
which is sometimes a solveable problem. (Recovering missing trees and
which is sometimes a solvable problem. (Recovering missing trees and
especially commits is *much* harder).
Before starting, verify that there is corruption, and figure out where

View File

@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.5.4-rc0.GIT
DEF_VER=v1.5.4-rc1.GIT
LF='
'

View File

@@ -230,7 +230,7 @@ SCRIPT_SH = \
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
git-filter-branch.sh \
git-stash.sh \
git-browse-help.sh
git-help--browse.sh
SCRIPT_PERL = \
git-add--interactive.perl \
@@ -923,6 +923,7 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
-e '/@@GITWEB_CGI@@/d' \
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
-e '/@@GITWEB_CSS@@/d' \
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
$@.sh > $@+ && \
chmod +x $@+ && \
mv $@+ $@
@@ -976,7 +977,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
builtin-revert.o builtin-runstatus.o wt-status.o: wt-status.h
builtin-revert.o wt-status.o: wt-status.h
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
@@ -1190,9 +1191,8 @@ check-docs::
case "$$v" in \
git-merge-octopus | git-merge-ours | git-merge-recursive | \
git-merge-resolve | git-merge-stupid | git-merge-subtree | \
git-add--interactive | git-fsck-objects | git-init-db | \
git-rebase--interactive | \
git-repo-config | git-fetch--tool ) continue ;; \
git-fsck-objects | git-init-db | git-repo-config | \
git-?*--?* ) continue ;; \
esac ; \
test -f "Documentation/$$v.txt" || \
echo "no doc: $$v"; \

View File

@@ -900,56 +900,22 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
static void check_whitespace(const char *line, int len, unsigned ws_rule)
{
const char *err = "Adds trailing whitespace";
int seen_space = 0;
int i;
char *err;
unsigned result = check_and_emit_line(line + 1, len - 1, ws_rule,
NULL, NULL, NULL, NULL);
if (!result)
return;
/*
* We know len is at least two, since we have a '+' and we
* checked that the last character was a '\n' before calling
* this function. That is, an addition of an empty line would
* check the '+' here. Sneaky...
*/
if ((ws_rule & WS_TRAILING_SPACE) && isspace(line[len-2]))
goto error;
/*
* Make sure that there is no space followed by a tab in
* indentation.
*/
if (ws_rule & WS_SPACE_BEFORE_TAB) {
err = "Space in indent is followed by a tab";
for (i = 1; i < len; i++) {
if (line[i] == '\t') {
if (seen_space)
goto error;
}
else if (line[i] == ' ')
seen_space = 1;
else
break;
}
}
/*
* Make sure that the indentation does not contain more than
* 8 spaces.
*/
if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
(8 < len) && !strncmp("+ ", line, 9)) {
err = "Indent more than 8 places with spaces";
goto error;
}
return;
error:
whitespace_error++;
if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error)
;
else
fprintf(stderr, "%s.\n%s:%d:%.*s\n",
err, patch_input_file, linenr, len-2, line+1);
else {
err = whitespace_error_string(result);
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
patch_input_file, linenr, err, len - 2, line + 1);
free(err);
}
}
/*
@@ -1584,8 +1550,8 @@ static int apply_line(char *output, const char *patch, int plen,
int i;
int add_nl_to_tail = 0;
int fixed = 0;
int last_tab_in_indent = -1;
int last_space_in_indent = -1;
int last_tab_in_indent = 0;
int last_space_in_indent = 0;
int need_fix_leading_space = 0;
char *buf;
@@ -1616,13 +1582,12 @@ static int apply_line(char *output, const char *patch, int plen,
if (ch == '\t') {
last_tab_in_indent = i;
if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
0 <= last_space_in_indent)
0 < last_space_in_indent)
need_fix_leading_space = 1;
} else if (ch == ' ') {
last_space_in_indent = i;
if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
last_tab_in_indent < 0 &&
8 <= i)
8 <= i - last_tab_in_indent)
need_fix_leading_space = 1;
}
else

View File

@@ -125,7 +125,6 @@ static void origin_decref(struct origin *o)
if (o && --o->refcnt <= 0) {
if (o->file.ptr)
free(o->file.ptr);
memset(o, 0, sizeof(*o));
free(o);
}
}
@@ -542,7 +541,7 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o,
state.ret->chunks = NULL;
state.ret->num = 0;
xdl_diff(file_p, file_o, &xpp, &xecfg, &ecb);
xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb);
if (state.ret->num) {
struct chunk *chunk;

View File

@@ -280,7 +280,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
return false_lock.filename;
}
static int run_status(FILE *fp, const char *index_file, const char *prefix)
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn)
{
struct wt_status s;
@@ -296,6 +296,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix)
s.untracked = untracked_files;
s.index_file = index_file;
s.fp = fp;
s.nowarn = nowarn;
wt_status_print(&s);
@@ -412,7 +413,7 @@ static int prepare_log_message(const char *index_file, const char *prefix)
saved_color_setting = wt_status_use_color;
wt_status_use_color = 0;
commitable = run_status(fp, index_file, prefix);
commitable = run_status(fp, index_file, prefix, 1);
wt_status_use_color = saved_color_setting;
fclose(fp);
@@ -536,7 +537,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
die("Option -m cannot be combined with -c/-C/-F.");
if (edit_message)
use_message = edit_message;
if (amend)
if (amend && !use_message)
use_message = "HEAD";
if (use_message) {
unsigned char sha1[20];
@@ -606,7 +607,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
index_file = prepare_index(argc, argv, prefix);
commitable = run_status(stdout, index_file, prefix);
commitable = run_status(stdout, index_file, prefix, 0);
rollback_index_files();
@@ -661,6 +662,10 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
rev.show_root_diff = 1;
rev.commit_format = get_commit_format("format:%h: %s");
rev.always_show_header = 0;
rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 100;
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
printf("Created %scommit ", initial_commit ? "initial " : "");
@@ -717,7 +722,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!prepare_log_message(index_file, prefix) && !in_merge &&
!allow_empty && !(amend && is_a_merge(head_sha1))) {
run_status(stdout, index_file, prefix);
run_status(stdout, index_file, prefix, 0);
rollback_index_files();
unlink(commit_editmsg);
return 1;

View File

@@ -267,12 +267,14 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
if (contains) {
const char **args = xmalloc((4 + argc) * sizeof(char*));
args[0] = "name-rev";
args[1] = "--name-only";
args[2] = "--tags";
memcpy(args + 3, argv, argc * sizeof(char*));
args[3 + argc] = NULL;
return cmd_name_rev(3 + argc, args, prefix);
int i = 0;
args[i++] = "name-rev";
args[i++] = "--name-only";
if (!all)
args[i++] = "--tags";
memcpy(args + i, argv, argc * sizeof(char*));
args[i + argc] = NULL;
return cmd_name_rev(i + argc, args, prefix);
}
if (argc == 0) {

View File

@@ -31,7 +31,5 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
result = run_diff_files_cmd(&rev, argc, argv);
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
return result;
return diff_result_code(&rev.diffopt, result);
}

View File

@@ -44,7 +44,5 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
return -1;
}
result = run_diff_index(&rev, cached);
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
return result;
return diff_result_code(&rev.diffopt, result);
}

View File

@@ -117,23 +117,21 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
break;
}
if (!read_stdin)
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
if (read_stdin) {
if (opt->diffopt.detect_rename)
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
DIFF_SETUP_USE_CACHE);
while (fgets(line, sizeof(line), stdin)) {
unsigned char sha1[20];
if (opt->diffopt.detect_rename)
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
DIFF_SETUP_USE_CACHE);
while (fgets(line, sizeof(line), stdin)) {
unsigned char sha1[20];
if (get_sha1_hex(line, sha1)) {
fputs(line, stdout);
fflush(stdout);
if (get_sha1_hex(line, sha1)) {
fputs(line, stdout);
fflush(stdout);
}
else
diff_tree_stdin(line);
}
else
diff_tree_stdin(line);
}
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
return diff_result_code(&opt->diffopt, 0);
}

View File

@@ -244,7 +244,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
/* If the user asked for our exit code then don't start a
/*
* If the user asked for our exit code then don't start a
* pager or we would end up reporting its exit code instead.
*/
if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
@@ -351,9 +352,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
else
result = builtin_diff_combined(&rev, argc, argv,
ent, ents);
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
result = diff_result_code(&rev.diffopt, result);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
return result;

View File

@@ -244,7 +244,28 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
return cmd_log_walk(&rev);
}
static int show_object(const unsigned char *sha1, int suppress_header)
static void show_tagger(char *buf, int len, struct rev_info *rev)
{
char *email_end, *p;
unsigned long date;
int tz;
email_end = memchr(buf, '>', len);
if (!email_end)
return;
p = ++email_end;
while (isspace(*p))
p++;
date = strtoul(p, &p, 10);
while (isspace(*p))
p++;
tz = (int)strtol(p, NULL, 10);
printf("Tagger: %.*s\nDate: %s\n", (int)(email_end - buf), buf,
show_date(date, tz, rev->date_mode));
}
static int show_object(const unsigned char *sha1, int show_tag_object,
struct rev_info *rev)
{
unsigned long size;
enum object_type type;
@@ -254,11 +275,14 @@ static int show_object(const unsigned char *sha1, int suppress_header)
if (!buf)
return error("Could not read object %s", sha1_to_hex(sha1));
if (suppress_header)
while (offset < size && buf[offset++] != '\n') {
int new_offset = offset;
if (show_tag_object)
while (offset < size && buf[offset] != '\n') {
int new_offset = offset + 1;
while (new_offset < size && buf[new_offset++] != '\n')
; /* do nothing */
if (!prefixcmp(buf + offset, "tagger "))
show_tagger(buf + offset + 7,
new_offset - offset - 7, rev);
offset = new_offset;
}
@@ -299,16 +323,16 @@ int cmd_show(int argc, const char **argv, const char *prefix)
const char *name = objects[i].name;
switch (o->type) {
case OBJ_BLOB:
ret = show_object(o->sha1, 0);
ret = show_object(o->sha1, 0, NULL);
break;
case OBJ_TAG: {
struct tag *t = (struct tag *)o;
printf("%stag %s%s\n\n",
printf("%stag %s%s\n",
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
t->tag,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
ret = show_object(o->sha1, 1);
ret = show_object(o->sha1, 1, &rev);
objects[i].item = (struct object *)t->tagged;
i--;
break;

View File

@@ -1594,6 +1594,15 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
#ifdef THREADED_DELTA_SEARCH
/*
* The main thread waits on the condition that (at least) one of the workers
* has stopped working (which is indicated in the .working member of
* struct thread_params).
* When a work thread has completed its work, it sets .working to 0 and
* signals the main thread and waits on the condition that .data_ready
* becomes 1.
*/
struct thread_params {
pthread_t thread;
struct object_entry **list;
@@ -1601,37 +1610,50 @@ struct thread_params {
unsigned remaining;
int window;
int depth;
int working;
int data_ready;
pthread_mutex_t mutex;
pthread_cond_t cond;
unsigned *processed;
};
static pthread_mutex_t data_request = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t data_ready = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t data_provider = PTHREAD_MUTEX_INITIALIZER;
static struct thread_params *data_requester;
static pthread_cond_t progress_cond = PTHREAD_COND_INITIALIZER;
static void *threaded_find_deltas(void *arg)
{
struct thread_params *me = arg;
for (;;) {
pthread_mutex_lock(&data_request);
data_requester = me;
pthread_mutex_unlock(&data_provider);
pthread_mutex_lock(&data_ready);
pthread_mutex_unlock(&data_request);
if (!me->remaining)
return NULL;
while (me->remaining) {
find_deltas(me->list, &me->remaining,
me->window, me->depth, me->processed);
progress_lock();
me->working = 0;
pthread_cond_signal(&progress_cond);
progress_unlock();
/*
* We must not set ->data_ready before we wait on the
* condition because the main thread may have set it to 1
* before we get here. In order to be sure that new
* work is available if we see 1 in ->data_ready, it
* was initialized to 0 before this thread was spawned
* and we reset it to 0 right away.
*/
pthread_mutex_lock(&me->mutex);
while (!me->data_ready)
pthread_cond_wait(&me->cond, &me->mutex);
me->data_ready = 0;
pthread_mutex_unlock(&me->mutex);
}
/* leave ->working 1 so that this doesn't get more work assigned */
return NULL;
}
static void ll_find_deltas(struct object_entry **list, unsigned list_size,
int window, int depth, unsigned *processed)
{
struct thread_params *target, p[delta_search_threads];
struct thread_params p[delta_search_threads];
int i, ret, active_threads = 0;
if (delta_search_threads <= 1) {
@@ -1639,49 +1661,42 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
return;
}
pthread_mutex_lock(&data_provider);
pthread_mutex_lock(&data_ready);
/* Start work threads. */
for (i = 0; i < delta_search_threads; i++) {
p[i].window = window;
p[i].depth = depth;
p[i].processed = processed;
p[i].remaining = 0;
ret = pthread_create(&p[i].thread, NULL,
threaded_find_deltas, &p[i]);
if (ret)
die("unable to create thread: %s", strerror(ret));
active_threads++;
}
/* Then partition the work amongst them. */
/* Partition the work amongst work threads. */
for (i = 0; i < delta_search_threads; i++) {
unsigned sub_size = list_size / (delta_search_threads - i);
pthread_mutex_lock(&data_provider);
target = data_requester;
if (!sub_size) {
pthread_mutex_unlock(&data_ready);
pthread_join(target->thread, NULL);
active_threads--;
continue;
}
p[i].window = window;
p[i].depth = depth;
p[i].processed = processed;
p[i].working = 1;
p[i].data_ready = 0;
/* try to split chunks on "path" boundaries */
while (sub_size < list_size && list[sub_size]->hash &&
list[sub_size]->hash == list[sub_size-1]->hash)
sub_size++;
target->list = list;
target->list_size = sub_size;
target->remaining = sub_size;
pthread_mutex_unlock(&data_ready);
p[i].list = list;
p[i].list_size = sub_size;
p[i].remaining = sub_size;
list += sub_size;
list_size -= sub_size;
}
/* Start work threads. */
for (i = 0; i < delta_search_threads; i++) {
if (!p[i].list_size)
continue;
pthread_mutex_init(&p[i].mutex, NULL);
pthread_cond_init(&p[i].cond, NULL);
ret = pthread_create(&p[i].thread, NULL,
threaded_find_deltas, &p[i]);
if (ret)
die("unable to create thread: %s", strerror(ret));
active_threads++;
}
/*
* Now let's wait for work completion. Each time a thread is done
* with its work, we steal half of the remaining work from the
@@ -1690,13 +1705,21 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
* until the remaining object list segments are simply too short
* to be worth splitting anymore.
*/
do {
while (active_threads) {
struct thread_params *target = NULL;
struct thread_params *victim = NULL;
unsigned sub_size = 0;
pthread_mutex_lock(&data_provider);
target = data_requester;
progress_lock();
for (;;) {
for (i = 0; !target && i < delta_search_threads; i++)
if (!p[i].working)
target = &p[i];
if (target)
break;
pthread_cond_wait(&progress_cond, &progress_mutex);
}
for (i = 0; i < delta_search_threads; i++)
if (p[i].remaining > 2*window &&
(!victim || victim->remaining < p[i].remaining))
@@ -1723,17 +1746,23 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
victim->list_size -= sub_size;
victim->remaining -= sub_size;
}
progress_unlock();
target->list_size = sub_size;
target->remaining = sub_size;
pthread_mutex_unlock(&data_ready);
target->working = 1;
progress_unlock();
pthread_mutex_lock(&target->mutex);
target->data_ready = 1;
pthread_cond_signal(&target->cond);
pthread_mutex_unlock(&target->mutex);
if (!sub_size) {
pthread_join(target->thread, NULL);
pthread_cond_destroy(&target->cond);
pthread_mutex_destroy(&target->mutex);
active_threads--;
}
} while (active_threads);
}
}
#else

View File

@@ -260,7 +260,7 @@ static int diff_two(const char *file1, const char *label1,
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
ecb.outf = outf;
xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);

View File

@@ -1,38 +0,0 @@
#include "builtin.h"
#include "cache.h"
#include "wt-status.h"
extern int wt_status_use_color;
static const char runstatus_usage[] =
"git-runstatus [--color|--nocolor] [--amend] [--verbose] [--untracked]";
int cmd_runstatus(int argc, const char **argv, const char *prefix)
{
struct wt_status s;
int i;
git_config(git_status_config);
wt_status_prepare(&s);
s.prefix = prefix;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--color"))
wt_status_use_color = 1;
else if (!strcmp(argv[i], "--nocolor"))
wt_status_use_color = 0;
else if (!strcmp(argv[i], "--amend")) {
s.amend = 1;
s.reference = "HEAD^1";
}
else if (!strcmp(argv[i], "--verbose"))
s.verbose = 1;
else if (!strcmp(argv[i], "--untracked"))
s.untracked = 1;
else
usage(runstatus_usage);
}
wt_status_print(&s);
return s.commitable ? 0 : 1;
}

View File

@@ -670,6 +670,10 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i
extern unsigned whitespace_rule_cfg;
extern unsigned whitespace_rule(const char *);
extern unsigned parse_whitespace_rule(const char *);
extern unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule,
FILE *stream, const char *set,
const char *reset, const char *ws);
extern char *whitespace_error_string(unsigned ws);
/* ls-files */
int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);

View File

@@ -226,7 +226,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
state.num_parent = num_parent;
state.n = n;
xdl_diff(&parent_file, result_file, &xpp, &xecfg, &ecb);
xdi_diff(&parent_file, result_file, &xpp, &xecfg, &ecb);
free(parent_file.ptr);
/* Assign line numbers for this parent.

View File

@@ -98,7 +98,6 @@ git-revert mainporcelain
git-rev-list plumbinginterrogators
git-rev-parse ancillaryinterrogators
git-rm mainporcelain common
git-runstatus ancillaryinterrogators
git-send-email foreignscminterface
git-send-pack synchingrepositories
git-shell synchelpers

View File

@@ -610,46 +610,36 @@ static int write_error(void)
static int store_write_section(int fd, const char* key)
{
const char *dot = strchr(key, '.');
int len1 = store.baselen, len2 = -1;
const char *dot;
int i, success;
struct strbuf sb;
dot = strchr(key, '.');
strbuf_init(&sb, 0);
dot = memchr(key, '.', store.baselen);
if (dot) {
int dotlen = dot - key;
if (dotlen < len1) {
len2 = len1 - dotlen - 1;
len1 = dotlen;
strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
for (i = dot - key + 1; i < store.baselen; i++) {
if (key[i] == '"')
strbuf_addch(&sb, '\\');
strbuf_addch(&sb, key[i]);
}
strbuf_addstr(&sb, "\"]\n");
} else {
strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
}
if (write_in_full(fd, "[", 1) != 1 ||
write_in_full(fd, key, len1) != len1)
return 0;
if (len2 >= 0) {
if (write_in_full(fd, " \"", 2) != 2)
return 0;
while (--len2 >= 0) {
unsigned char c = *++dot;
if (c == '"')
if (write_in_full(fd, "\\", 1) != 1)
return 0;
if (write_in_full(fd, &c, 1) != 1)
return 0;
}
if (write_in_full(fd, "\"", 1) != 1)
return 0;
}
if (write_in_full(fd, "]\n", 2) != 2)
return 0;
success = write_in_full(fd, sb.buf, sb.len) == sb.len;
strbuf_release(&sb);
return 1;
return success;
}
static int store_write_pair(int fd, const char* key, const char* value)
{
int i;
int length = strlen(key+store.baselen+1);
int quote = 0;
int i, success;
int length = strlen(key + store.baselen + 1);
const char *quote = "";
struct strbuf sb;
/*
* Check to see if the value needs to be surrounded with a dq pair.
@@ -659,43 +649,38 @@ static int store_write_pair(int fd, const char* key, const char* value)
* configuration parser.
*/
if (value[0] == ' ')
quote = 1;
quote = "\"";
for (i = 0; value[i]; i++)
if (value[i] == ';' || value[i] == '#')
quote = 1;
if (i && value[i-1] == ' ')
quote = 1;
quote = "\"";
if (i && value[i - 1] == ' ')
quote = "\"";
strbuf_init(&sb, 0);
strbuf_addf(&sb, "\t%.*s = %s",
length, key + store.baselen + 1, quote);
if (write_in_full(fd, "\t", 1) != 1 ||
write_in_full(fd, key+store.baselen+1, length) != length ||
write_in_full(fd, " = ", 3) != 3)
return 0;
if (quote && write_in_full(fd, "\"", 1) != 1)
return 0;
for (i = 0; value[i]; i++)
switch (value[i]) {
case '\n':
if (write_in_full(fd, "\\n", 2) != 2)
return 0;
strbuf_addstr(&sb, "\\n");
break;
case '\t':
if (write_in_full(fd, "\\t", 2) != 2)
return 0;
strbuf_addstr(&sb, "\\t");
break;
case '"':
case '\\':
if (write_in_full(fd, "\\", 1) != 1)
return 0;
strbuf_addch(&sb, '\\');
default:
if (write_in_full(fd, value+i, 1) != 1)
return 0;
strbuf_addch(&sb, value[i]);
break;
}
if (quote && write_in_full(fd, "\"", 1) != 1)
return 0;
if (write_in_full(fd, "\n", 1) != 1)
return 0;
return 1;
strbuf_addf(&sb, "%s\n", quote);
success = write_in_full(fd, sb.buf, sb.len) == sb.len;
strbuf_release(&sb);
return success;
}
static ssize_t find_beginning_of_line(const char* contents, size_t size,

View File

@@ -291,7 +291,7 @@ __git_commands ()
for i in $(git help -a|egrep '^ ')
do
case $i in
add--interactive) : plumbing;;
*--*) : helper pattern;;
applymbox) : ask gittus;;
applypatch) : ask gittus;;
archimport) : import;;
@@ -308,7 +308,6 @@ __git_commands ()
diff-tree) : plumbing;;
fast-import) : import;;
fsck-objects) : plumbing;;
fetch--tool) : plumbing;;
fetch-pack) : plumbing;;
fmt-merge-msg) : plumbing;;
for-each-ref) : plumbing;;

View File

@@ -212,11 +212,24 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
if (hash_count[i] <= HASH_LIMIT)
continue;
entries -= hash_count[i] - HASH_LIMIT;
/* We leave exactly HASH_LIMIT entries in the bucket */
entries -= hash_count[i] - HASH_LIMIT;
entry = hash[i];
acc = 0;
/*
* Assume that this loop is gone through exactly
* HASH_LIMIT times and is entered and left with
* acc==0. So the first statement in the loop
* contributes (hash_count[i]-HASH_LIMIT)*HASH_LIMIT
* to the accumulator, and the inner loop consequently
* is run (hash_count[i]-HASH_LIMIT) times, removing
* one element from the list each time. Since acc
* balances out to 0 at the final run, the inner loop
* body can't be left with entry==NULL. So we indeed
* encounter entry==NULL in the outer loop only.
*/
do {
acc += hash_count[i] - HASH_LIMIT;
if (acc > 0) {
@@ -229,30 +242,17 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
}
entry = entry->next;
} while (entry);
/* Assume that this loop is gone through exactly
* HASH_LIMIT times and is entered and left with
* acc==0. So the first statement in the loop
* contributes (hash_count[i]-HASH_LIMIT)*HASH_LIMIT
* to the accumulator, and the inner loop consequently
* is run (hash_count[i]-HASH_LIMIT) times, removing
* one element from the list each time. Since acc
* balances out to 0 at the final run, the inner loop
* body can't be left with entry==NULL. So we indeed
* encounter entry==NULL in the outer loop only.
*/
}
free(hash_count);
/* Now create the packed index in array form rather than
* linked lists */
/*
* Now create the packed index in array form
* rather than linked lists.
*/
memsize = sizeof(*index)
+ sizeof(*packed_hash) * (hsize+1)
+ sizeof(*packed_entry) * entries;
mem = malloc(memsize);
if (!mem) {
free(hash);
return NULL;
@@ -264,24 +264,24 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
index->src_size = bufsize;
index->hash_mask = hmask;
mem = index + 1;
mem = index->hash;
packed_hash = mem;
mem = packed_hash + (hsize+1);
packed_entry = mem;
/* Coalesce all entries belonging to one linked list into
* consecutive array entries */
for (i = 0; i < hsize; i++) {
/*
* Coalesce all entries belonging to one linked list
* into consecutive array entries.
*/
packed_hash[i] = packed_entry;
for (entry = hash[i]; entry; entry = entry->next)
*packed_entry++ = entry->entry;
}
/* Sentinel value to indicate the length of the last hash
* bucket */
/* Sentinel value to indicate the length of the last hash bucket */
packed_hash[hsize] = packed_entry;
assert(packed_entry - (struct index_entry *)mem == entries);
free(hash);

170
diff.c
View File

@@ -20,6 +20,7 @@
static int diff_detect_rename_default;
static int diff_rename_limit_default = 100;
static int diff_use_color_default;
static const char *external_diff_cmd_cfg;
int diff_auto_refresh_index = 1;
static char diff_colors[][COLOR_MAXLEN] = {
@@ -163,6 +164,10 @@ int git_diff_ui_config(const char *var, const char *value)
diff_auto_refresh_index = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "diff.external")) {
external_diff_cmd_cfg = xstrdup(value);
return 0;
}
if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.');
@@ -209,6 +214,8 @@ static const char *external_diff(void)
if (done_preparing)
return external_diff_cmd;
external_diff_cmd = getenv("GIT_EXTERNAL_DIFF");
if (!external_diff_cmd)
external_diff_cmd = external_diff_cmd_cfg;
done_preparing = 1;
return external_diff_cmd;
}
@@ -439,7 +446,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
ecb.outf = xdiff_outf;
ecb.priv = diff_words;
diff_words->xm.consume = fn_out_diff_words_aux;
xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);
@@ -486,88 +493,9 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
static void emit_line(const char *set, const char *reset, const char *line, int len)
{
if (len > 0 && line[len-1] == '\n')
len--;
fputs(set, stdout);
fwrite(line, len, 1, stdout);
puts(reset);
}
static void emit_line_with_ws(int nparents,
const char *set, const char *reset, const char *ws,
const char *line, int len, unsigned ws_rule)
{
int col0 = nparents;
int last_tab_in_indent = -1;
int last_space_in_indent = -1;
int i;
int tail = len;
int need_highlight_leading_space = 0;
/*
* The line is a newly added line. Does it have funny leading
* whitespaces? In indent, SP should never precede a TAB. In
* addition, under "indent with non tab" rule, there should not
* be more than 8 consecutive spaces.
*/
for (i = col0; i < len; i++) {
if (line[i] == '\t') {
last_tab_in_indent = i;
if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
0 <= last_space_in_indent)
need_highlight_leading_space = 1;
}
else if (line[i] == ' ')
last_space_in_indent = i;
else
break;
}
if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
0 <= last_space_in_indent &&
last_tab_in_indent < 0 &&
8 <= (i - col0)) {
last_tab_in_indent = i;
need_highlight_leading_space = 1;
}
fputs(set, stdout);
fwrite(line, col0, 1, stdout);
fputs(reset, stdout);
if (((i == len) || line[i] == '\n') && i != col0) {
/* The whole line was indent */
emit_line(ws, reset, line + col0, len - col0);
return;
}
i = col0;
if (need_highlight_leading_space) {
while (i < last_tab_in_indent) {
if (line[i] == ' ') {
fputs(ws, stdout);
putchar(' ');
fputs(reset, stdout);
}
else
putchar(line[i]);
i++;
}
}
tail = len - 1;
if (line[tail] == '\n' && i < tail)
tail--;
if (ws_rule & WS_TRAILING_SPACE) {
while (i < tail) {
if (!isspace(line[tail]))
break;
tail--;
}
}
if ((i < tail && line[tail + 1] != '\n')) {
/* This has whitespace between tail+1..len */
fputs(set, stdout);
fwrite(line + i, tail - i + 1, 1, stdout);
fputs(reset, stdout);
emit_line(ws, reset, line + tail + 1, len - tail - 1);
}
else
emit_line(set, reset, line + i, len - i);
}
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
@@ -577,9 +505,13 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
if (!*ws)
emit_line(set, reset, line, len);
else
emit_line_with_ws(ecbdata->nparents, set, reset, ws,
line, len, ecbdata->ws_rule);
else {
/* Emit just the prefix, then the rest. */
emit_line(set, reset, line, ecbdata->nparents);
(void)check_and_emit_line(line + ecbdata->nparents,
len - ecbdata->nparents, ecbdata->ws_rule,
stdout, set, reset, ws);
}
}
static void fn_out_consume(void *priv, char *line, unsigned long len)
@@ -1031,6 +963,7 @@ struct checkdiff_t {
const char *filename;
int lineno, color_diff;
unsigned ws_rule;
unsigned status;
};
static void checkdiff_consume(void *priv, char *line, unsigned long len)
@@ -1039,44 +972,19 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE);
const char *reset = diff_get_color(data->color_diff, DIFF_RESET);
const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW);
char *err;
if (line[0] == '+') {
int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
/* check space before tab */
for (i = 1; i < len; i++) {
if (line[i] == ' ')
spaces++;
else if (line[i] == '\t') {
if (spaces) {
space_before_tab = 1;
break;
}
}
else
break;
}
/* check whitespace at line end */
if (line[len - 1] == '\n')
len--;
if (isspace(line[len - 1]))
white_space_at_end = 1;
if (space_before_tab || white_space_at_end) {
printf("%s:%d: %s", data->filename, data->lineno, ws);
if (space_before_tab) {
printf("space before tab");
if (white_space_at_end)
putchar(',');
}
if (white_space_at_end)
printf("whitespace at end");
printf(":%s ", reset);
emit_line_with_ws(1, set, reset, ws, line, len,
data->ws_rule);
}
data->status = check_and_emit_line(line + 1, len - 1,
data->ws_rule, NULL, NULL, NULL, NULL);
if (!data->status)
return;
err = whitespace_error_string(data->status);
printf("%s:%d: %s.\n", data->filename, data->lineno, err);
free(err);
emit_line(set, reset, line, 1);
(void)check_and_emit_line(line + 1, len - 1, data->ws_rule,
stdout, set, reset, ws);
data->lineno++;
} else if (line[0] == ' ')
data->lineno++;
@@ -1393,7 +1301,7 @@ static void builtin_diff(const char *name_a,
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
free_diff_words_data(&ecbdata);
}
@@ -1446,7 +1354,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
ecb.outf = xdiff_outf;
ecb.priv = diffstat;
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
free_and_return:
@@ -1486,11 +1394,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
xpp.flags = XDF_NEED_MINIMAL;
ecb.outf = xdiff_outf;
ecb.priv = &data;
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
free_and_return:
diff_free_filespec_data(one);
diff_free_filespec_data(two);
if (data.status)
DIFF_OPT_SET(o, CHECK_FAILED);
}
struct diff_filespec *alloc_filespec(const char *path)
@@ -2898,7 +2808,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
xecfg.flags = XDL_EMIT_FUNCNAMES;
ecb.outf = xdiff_outf;
ecb.priv = &data;
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
SHA1_Final(sha1, &ctx);
@@ -3171,6 +3081,20 @@ void diffcore_std(struct diff_options *options)
DIFF_OPT_CLR(options, HAS_CHANGES);
}
int diff_result_code(struct diff_options *opt, int status)
{
int result = 0;
if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
!(opt->output_format & DIFF_FORMAT_CHECKDIFF))
return status;
if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
DIFF_OPT_TST(opt, HAS_CHANGES))
result |= 01;
if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) &&
DIFF_OPT_TST(opt, CHECK_FAILED))
result |= 02;
return result;
}
void diff_addremove(struct diff_options *options,
int addremove, unsigned mode,

3
diff.h
View File

@@ -59,6 +59,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
#define DIFF_OPT_ALLOW_EXTERNAL (1 << 13)
#define DIFF_OPT_EXIT_WITH_STATUS (1 << 14)
#define DIFF_OPT_REVERSE_DIFF (1 << 15)
#define DIFF_OPT_CHECK_FAILED (1 << 16)
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
@@ -246,4 +247,6 @@ 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_result_code(struct diff_options *, int);
#endif /* DIFF_H */

3
dir.c
View File

@@ -169,7 +169,10 @@ static int add_excludes_from_file_1(const char *fname,
}
buf = xmalloc(size+1);
if (read_in_full(fd, buf, size) != size)
{
free(buf);
goto err;
}
close(fd);
if (buf_p)

View File

@@ -196,7 +196,7 @@ struct mem_pool
struct mem_pool *next_pool;
char *next_free;
char *end;
char space[FLEX_ARRAY]; /* more */
uintmax_t space[FLEX_ARRAY]; /* more */
};
struct atom_str
@@ -536,15 +536,15 @@ static void *pool_alloc(size_t len)
total_allocd += sizeof(struct mem_pool) + mem_pool_alloc;
p = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc);
p->next_pool = mem_pool;
p->next_free = p->space;
p->next_free = (char *) p->space;
p->end = p->next_free + mem_pool_alloc;
mem_pool = p;
}
r = p->next_free;
/* round out to a pointer alignment */
if (len & (sizeof(void*) - 1))
len += sizeof(void*) - (len & (sizeof(void*) - 1));
/* round out to a 'uintmax_t' alignment */
if (len & (sizeof(uintmax_t) - 1))
len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
p->next_free += len;
return r;
}

View File

@@ -93,11 +93,12 @@ fi
http_fetch () {
# $1 = Remote, $2 = Local
curl -nsfL $curl_extra_args "$1" >"$2" ||
case $? in
126|127) exit ;;
*) return $? ;;
esac
curl -nsfL $curl_extra_args "$1" >"$2"
curl_exit_status=$?
case $curl_exit_status in
126|127) exit ;;
*) return $curl_exit_status ;;
esac
}
clone_dumb_http () {
@@ -190,7 +191,7 @@ do
die "clones are always made with separate-remote layout" ;;
--reference)
shift; reference="$1" ;;
-o,--origin)
-o|--origin)
shift;
case "$1" in
'')

View File

@@ -195,11 +195,11 @@ foreach my $f (@files) {
my %cvsstat;
if (@canstatusfiles) {
if ($opt_u) {
my @updated = safe_pipe_capture(@cvs, 'update', @canstatusfiles);
my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles);
print @updated;
}
my @cvsoutput;
@cvsoutput= safe_pipe_capture(@cvs, 'status', @canstatusfiles);
@cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles);
my $matchcount = 0;
foreach my $l (@cvsoutput) {
chomp $l;
@@ -295,7 +295,7 @@ if ($dirtypatch) {
if ($opt_c) {
print "Autocommit\n $cmd\n";
print safe_pipe_capture(@cvs, 'commit', '-F', '.msg', @files);
print xargs_safe_pipe_capture([@cvs, 'commit', '-F', '.msg'], @files);
if ($?) {
die "Exiting: The commit did not succeed";
}
@@ -335,15 +335,24 @@ sub safe_pipe_capture {
return wantarray ? @output : join('',@output);
}
sub safe_pipe_capture_blob {
my $output;
if (my $pid = open my $child, '-|') {
local $/;
undef $/;
$output = (<$child>);
close $child or die join(' ',@_).": $! $?";
} else {
exec(@_) or die "$! $?"; # exec() can fail the executable can't be found
}
return $output;
sub xargs_safe_pipe_capture {
my $MAX_ARG_LENGTH = 65536;
my $cmd = shift;
my @output;
my $output;
while(@_) {
my @args;
my $length = 0;
while(@_ && $length < $MAX_ARG_LENGTH) {
push @args, shift;
$length += length($args[$#args]);
}
if (wantarray) {
push @output, safe_pipe_capture(@$cmd, @args);
}
else {
$output .= safe_pipe_capture(@$cmd, @args);
}
}
return wantarray ? @output : $output;
}

View File

@@ -290,7 +290,7 @@ while read commit parents; do
eval "$filter_tree" < /dev/null ||
die "tree filter failed: $filter_tree"
git diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
git diff-index -r $commit | cut -f 2- | tr '\012' '\000' | \
xargs -0 git update-index --add --replace --remove
git ls-files -z --others | \
xargs -0 git update-index --add --replace --remove
@@ -342,7 +342,6 @@ done < "$tempdir"/heads
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
count=0
echo
while read ref
do
@@ -380,7 +379,6 @@ do
;;
esac
git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1
count=$(($count+1))
done < "$tempdir"/heads
# TODO: This should possibly go, with the semantics that all positive given
@@ -423,9 +421,6 @@ fi
cd ../..
rm -rf "$tempdir"
echo
test $count -gt 0 && echo "These refs were rewritten:"
git show-ref | grep ^"$orig_namespace"
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
test -z "$ORIG_GIT_DIR" || GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR

View File

@@ -39,7 +39,7 @@ valid_tool() {
}
init_browser_path() {
test -z "$GIT_DIR" || browser_path=`git config browser.$1.path`
browser_path=`git config browser.$1.path`
test -z "$browser_path" && browser_path=$1
}
@@ -71,7 +71,7 @@ do
shift
done
if test -z "$browser" && test -n "$GIT_DIR"
if test -z "$browser"
then
for opt in "help.browser" "web.browser"
do

View File

@@ -3,6 +3,7 @@
# Copyright (c) 2006 Eric Wong
#
PERL='@@PERL@@'
OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git-instaweb [options] (--start | --stop | --restart)
@@ -232,16 +233,18 @@ EOF
}
script='
s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'$(dirname "$fqgitdir")'";#
s#\(my\|our\) $gitbin =.*#\1 $gitbin = "'$GIT_EXEC_PATH'";#
s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;#
s#\(my\|our\) $git_temp =.*#\1 $git_temp = "'$fqgitdir/gitweb/tmp'";#'
s#^(my|our) \$projectroot =.*#$1 \$projectroot = "'$(dirname "$fqgitdir")'";#;
s#(my|our) \$gitbin =.*#$1 \$gitbin = "'$GIT_EXEC_PATH'";#;
s#(my|our) \$projects_list =.*#$1 \$projects_list = \$projectroot;#;
s#(my|our) \$git_temp =.*#$1 \$git_temp = "'$fqgitdir/gitweb/tmp'";#;'
gitweb_cgi () {
cat > "$1.tmp" <<\EOFGITWEB
@@GITWEB_CGI@@
EOFGITWEB
sed "$script" "$1.tmp" > "$1"
# Use the configured full path to perl to match the generated
# scripts' 'hashpling' line
"$PERL" -p -e "$script" "$1.tmp" > "$1"
chmod +x "$1"
rm -f "$1.tmp"
}
@@ -273,4 +276,4 @@ esac
start_httpd
url=http://127.0.0.1:$port
"$browser" $url || echo $url
test -n "$browser" && "$browser" $url || echo $url

View File

@@ -289,22 +289,22 @@ do_next () {
output git reset --soft HEAD^
pick_one -n $sha1 || failed=t
echo "$author_script" > "$DOTEST"/author-script
case $failed in
f)
if test $failed = f
then
# This is like --amend, but with a different message
eval "$author_script"
GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
$USE_OUTPUT git commit -F "$MSG" $EDIT_COMMIT
;;
t)
$USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT || failed=t
fi
if test $failed = t
then
cp "$MSG" "$GIT_DIR"/MERGE_MSG
warn
warn "Could not apply $sha1... $rest"
die_with_patch $sha1 ""
;;
esac
fi
;;
*)
warn "Unknown command: $command $sha1 $rest"
@@ -322,7 +322,12 @@ do_next () {
test -f "$DOTEST"/current-commit &&
current_commit=$(cat "$DOTEST"/current-commit) &&
git rev-parse HEAD > "$REWRITTEN"/$current_commit
NEWHEAD=$(cat "$REWRITTEN"/$OLDHEAD)
if test -f "$REWRITTEN"/$OLDHEAD
then
NEWHEAD=$(cat "$REWRITTEN"/$OLDHEAD)
else
NEWHEAD=$OLDHEAD
fi
else
NEWHEAD=$(git rev-parse HEAD)
fi &&
@@ -366,8 +371,9 @@ do
. "$DOTEST"/author-script && {
test ! -f "$DOTEST"/amend || git reset --soft HEAD^
} &&
export GIT_AUTHOR_NAME GIT_AUTHOR_NAME GIT_AUTHOR_DATE &&
git commit -F "$DOTEST"/message -e
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE &&
git commit --no-verify -F "$DOTEST"/message -e ||
die "Could not commit staged changes."
require_clean_work_tree
do_rest

View File

@@ -580,7 +580,7 @@ sub send_message
$ccline = "\nCc: $cc";
}
my $sanitized_sender = sanitize_address($sender);
make_message_id();
make_message_id() unless defined($message_id);
my $header = "From: $sanitized_sender
To: $to${ccline}
@@ -718,6 +718,9 @@ foreach my $t (@files) {
}
push @xh, $_;
}
elsif (/^Message-Id: (.*)/i) {
$message_id = $1;
}
elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_;
}
@@ -805,6 +808,7 @@ foreach my $t (@files) {
$references = "$message_id";
}
}
$message_id = undef;
}
if ($compose) {

View File

@@ -124,13 +124,8 @@ get_author_ident_from_commit () {
# Make sure we are in a valid repository of a vintage we understand,
# if we require to be in a git repository.
if test -n "$NONGIT_OK"
if test -z "$NONGIT_OK"
then
if git rev-parse --git-dir >/dev/null 2>&1
then
: ${GIT_DIR=.git}
fi
else
if [ -z "$SUBDIRECTORY_OK" ]
then
: ${GIT_DIR=.git}

View File

@@ -197,8 +197,8 @@ for (my $i = 0; $i < @ARGV; $i++) {
}
};
# make sure we're always running
unless ($cmd =~ /(?:clone|init|multi-init)$/) {
# make sure we're always running at the top-level working directory
unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {
unless (-d $ENV{GIT_DIR}) {
if ($git_dir_user_set) {
die "GIT_DIR=$ENV{GIT_DIR} explicitly set, ",
@@ -396,6 +396,7 @@ sub cmd_set_tree {
}
$gs->set_tree($_) foreach @revs;
print "Done committing ",scalar @revs," revisions to SVN\n";
unlink $gs->{index};
}
sub cmd_dcommit {
@@ -514,6 +515,7 @@ sub cmd_dcommit {
$last_rev = $cmt_rev;
}
}
unlink $gs->{index};
}
sub cmd_find_rev {
@@ -1374,6 +1376,7 @@ sub fetch_all {
($base, $head) = parse_revision_argument($base, $head);
$ra->gs_fetch_loop_common($base, $head, \@gs, \@globs);
unlink $_->{index} foreach @gs;
}
sub read_all_remotes {
@@ -2049,6 +2052,43 @@ sub full_url {
$self->{url} . (length $self->{path} ? '/' . $self->{path} : '');
}
sub set_commit_header_env {
my ($log_entry) = @_;
my %env;
foreach my $ned (qw/NAME EMAIL DATE/) {
foreach my $ac (qw/AUTHOR COMMITTER/) {
$env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"};
}
}
$ENV{GIT_AUTHOR_NAME} = $log_entry->{name};
$ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email};
$ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date};
$ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name})
? $log_entry->{commit_name}
: $log_entry->{name};
$ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email})
? $log_entry->{commit_email}
: $log_entry->{email};
\%env;
}
sub restore_commit_header_env {
my ($env) = @_;
foreach my $ned (qw/NAME EMAIL DATE/) {
foreach my $ac (qw/AUTHOR COMMITTER/) {
my $k = "GIT_${ac}_${ned}";
if (defined $env->{$k}) {
$ENV{$k} = $env->{$k};
} else {
delete $ENV{$k};
}
}
}
}
sub do_git_commit {
my ($self, $log_entry) = @_;
my $lr = $self->last_rev;
@@ -2061,17 +2101,7 @@ sub do_git_commit {
croak "$log_entry->{revision} = $c already exists! ",
"Why are we refetching it?\n";
}
$ENV{GIT_AUTHOR_NAME} = $log_entry->{name};
$ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email};
$ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date};
$ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name})
? $log_entry->{commit_name}
: $log_entry->{name};
$ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email})
? $log_entry->{commit_email}
: $log_entry->{email};
my $old_env = set_commit_header_env($log_entry);
my $tree = $log_entry->{tree};
if (!defined $tree) {
$tree = $self->tmp_index_do(sub {
@@ -2086,6 +2116,7 @@ sub do_git_commit {
defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))
or croak $!;
print $msg_fh $log_entry->{log} or croak $!;
restore_commit_header_env($old_env);
unless ($self->no_metadata) {
print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n"
or croak $!;
@@ -2363,11 +2394,20 @@ sub make_log_entry {
my ($commit_name, $commit_email) = ($name, $email);
if ($_use_log_author) {
if ($log_entry{log} =~ /From:\s+(.*?)\s+<(.*)>\s*\n/) {
($name, $email) = ($1, $2);
} elsif ($log_entry{log} =~
/Signed-off-by:\s+(.*?)\s+<(.*)>\s*\n/) {
my $name_field;
if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) {
$name_field = $1;
} elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) {
$name_field = $1;
}
if (!defined $name_field) {
#
} elsif ($name_field =~ /(.*?)\s+<(.*)>/) {
($name, $email) = ($1, $2);
} elsif ($name_field =~ /(.*)@/) {
($name, $email) = ($1, $name_field);
} else {
($name, $email) = ($name_field, 'unknown');
}
}
if (defined $headrev && $self->use_svm_props) {
@@ -3033,6 +3073,20 @@ sub add_file {
sub add_directory {
my ($self, $path, $cp_path, $cp_rev) = @_;
my $gpath = $self->git_path($path);
if ($gpath eq '') {
my ($ls, $ctx) = command_output_pipe(qw/ls-tree
-r --name-only -z/,
$self->{c});
local $/ = "\0";
while (<$ls>) {
chomp;
$self->{gii}->remove($_);
print "\tD\t$_\n" unless $::_q;
}
command_close_pipe($ls, $ctx);
$self->{empty}->{$path} = 0;
}
my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
delete $self->{empty}->{$dir};
$self->{empty}->{$path} = 1;
@@ -3123,9 +3177,15 @@ sub close_file {
}
sysseek($fh, 0, 0) or croak $!;
if ($fb->{mode_b} == 120000) {
sysread($fh, my $buf, 5) == 5 or croak $!;
$buf eq 'link ' or die "$path has mode 120000",
"but is not a link\n";
eval {
sysread($fh, my $buf, 5) == 5 or croak $!;
$buf eq 'link ' or die "$path has mode 120000",
" but is not a link";
};
if ($@) {
warn "$@\n";
sysseek($fh, 0, 0) or croak $!;
}
}
defined(my $pid = open my $out,'-|') or die "Can't fork: $!\n";
if (!$pid) {

View File

@@ -1511,7 +1511,7 @@ sub config_to_int {
sub config_to_multi {
my $val = shift;
return ref($val) ? $val : [ $val ];
return ref($val) ? $val : (defined($val) ? [ $val ] : []);
}
sub git_get_project_config {
@@ -2233,6 +2233,7 @@ sub git_get_heads_list {
my ($hash, $name, $title) = split(' ', $refinfo, 3);
my ($committer, $epoch, $tz) =
($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
$ref_item{'fullname'} = $name;
$name =~ s!^refs/heads/!!;
$ref_item{'name'} = $name;
@@ -2270,6 +2271,7 @@ sub git_get_tags_list {
my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6);
my ($creator, $epoch, $tz) =
($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/);
$ref_item{'fullname'} = $name;
$name =~ s!^refs/tags/!!;
$ref_item{'type'} = $type;
@@ -3690,8 +3692,8 @@ sub git_tags_body {
"<td class=\"link\">" . " | " .
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
if ($tag{'reftype'} eq "commit") {
print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") .
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log");
print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'fullname'})}, "shortlog") .
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'fullname'})}, "log");
} elsif ($tag{'reftype'} eq "blob") {
print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
}
@@ -3726,13 +3728,13 @@ sub git_heads_body {
$alternate ^= 1;
print "<td><i>$ref{'age'}</i></td>\n" .
($curr ? "<td class=\"current_head\">" : "<td>") .
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}),
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'}),
-class => "list name"},esc_html($ref{'name'})) .
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " .
$cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " .
$cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") .
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'})}, "shortlog") . " | " .
$cgi->a({-href => href(action=>"log", hash=>$ref{'fullname'})}, "log") . " | " .
$cgi->a({-href => href(action=>"tree", hash=>$ref{'fullname'}, hash_base=>$ref{'name'})}, "tree") .
"</td>\n" .
"</tr>";
}
@@ -4288,7 +4290,7 @@ sub git_blob {
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
or die_error(undef, "Couldn't cat $file_name, $hash");
my $mimetype = blob_mimetype($fd, $file_name);
if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)!) {
if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) {
close $fd;
return git_blob_plain($mimetype);
}
@@ -4329,16 +4331,7 @@ sub git_blob {
}
git_print_page_path($file_name, "blob", $hash_base);
print "<div class=\"page_body\">\n";
if ($mimetype =~ m!^text/!) {
my $nr;
while (my $line = <$fd>) {
chomp $line;
$nr++;
$line = untabify($line);
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
}
} elsif ($mimetype =~ m!^image/!) {
if ($mimetype =~ m!^image/!) {
print qq!<img type="$mimetype"!;
if ($file_name) {
print qq! alt="$file_name" title="$file_name"!;
@@ -4347,6 +4340,15 @@ sub git_blob {
href(action=>"blob_plain", hash=>$hash,
hash_base=>$hash_base, file_name=>$file_name) .
qq!" />\n!;
} else {
my $nr;
while (my $line = <$fd>) {
chomp $line;
$nr++;
$line = untabify($line);
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
}
}
close $fd
or print "Reading blob failed.\n";

74
help.c
View File

@@ -9,6 +9,48 @@
#include "common-cmds.h"
#include "dir.h"
static const char *help_default_format;
static enum help_format {
man_format,
info_format,
web_format,
#ifdef __MINGW32__
} help_format = web_format;
#else
} help_format = man_format;
#endif
static void parse_help_format(const char *format)
{
if (!format) {
help_format = man_format;
return;
}
if (!strcmp(format, "man")) {
help_format = man_format;
return;
}
if (!strcmp(format, "info")) {
help_format = info_format;
return;
}
if (!strcmp(format, "web") || !strcmp(format, "html")) {
help_format = web_format;
return;
}
die("unrecognized help format '%s'", format);
}
static int git_help_config(const char *var, const char *value)
{
if (!strcmp(var, "help.format")) {
help_default_format = xstrdup(value);
return 0;
}
return git_default_config(var, value);
}
/* most GUI terminals set COLUMNS (although some don't export it) */
static int term_columns(void)
{
@@ -318,7 +360,7 @@ static void show_html_page(const char *git_cmd)
}
#else
const char *page = cmd_to_page(git_cmd);
execl_git_cmd("browse-help", page, NULL);
execl_git_cmd("help--browse", page, NULL);
#endif
}
@@ -357,12 +399,30 @@ int cmd_help(int argc, const char **argv, const char *prefix)
show_info_page(argc > 2 ? argv[2] : NULL);
}
else
#ifdef __MINGW32__
show_html_page(help_cmd);
#else
show_man_page(help_cmd);
#endif
else if (!strcmp(help_cmd, "--man") || !strcmp(help_cmd, "-m")) {
show_man_page(argc > 2 ? argv[2] : NULL);
}
else {
int nongit;
setup_git_directory_gently(&nongit);
git_config(git_help_config);
if (help_default_format)
parse_help_format(help_default_format);
switch (help_format) {
case man_format:
show_man_page(help_cmd);
break;
case info_format:
show_info_page(help_cmd);
break;
case web_format:
show_html_page(help_cmd);
break;
}
}
return 0;
}

View File

@@ -75,7 +75,6 @@ static int aborted;
static signed char remote_dir_exists[256];
static struct curl_slist *no_pragma_header;
static struct curl_slist *default_headers;
static int push_verbosely;
static int push_all = MATCH_REFS_NONE;
@@ -495,10 +494,11 @@ static void start_put(struct transfer_request *request)
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, zlib_compression_level);
size = deflateBound(&stream, len + hdrlen);
request->buffer.buffer = xmalloc(size);
strbuf_init(&request->buffer.buf, size);
request->buffer.posn = 0;
/* Compress it */
stream.next_out = request->buffer.buffer;
stream.next_out = (unsigned char *)request->buffer.buf.buf;
stream.avail_out = size;
/* First header.. */
@@ -515,8 +515,7 @@ static void start_put(struct transfer_request *request)
deflateEnd(&stream);
free(unpacked);
request->buffer.size = stream.total_out;
request->buffer.posn = 0;
request->buffer.buf.len = stream.total_out;
request->url = xmalloc(strlen(remote->url) +
strlen(request->lock->token) + 51);
@@ -538,7 +537,7 @@ static void start_put(struct transfer_request *request)
slot->callback_func = process_response;
slot->callback_data = request;
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.size);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
@@ -925,11 +924,14 @@ static int fetch_index(unsigned char *sha1)
hex);
}
} else {
free(url);
return error("Unable to start request");
}
if (has_pack_index(sha1))
if (has_pack_index(sha1)) {
free(url);
return 0;
}
if (push_verbosely)
fprintf(stderr, "Getting index for pack %s\n", hex);
@@ -939,9 +941,11 @@ static int fetch_index(unsigned char *sha1)
filename = sha1_pack_index_name(sha1);
snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
indexfile = fopen(tmpfile, "a");
if (!indexfile)
if (!indexfile) {
free(url);
return error("Unable to open local file %s for pack index",
tmpfile);
}
slot = get_active_slot();
slot->results = &results;
@@ -1003,18 +1007,13 @@ static int fetch_indices(void)
{
unsigned char sha1[20];
char *url;
struct buffer buffer;
struct strbuf buffer = STRBUF_INIT;
char *data;
int i = 0;
struct active_request_slot *slot;
struct slot_results results;
data = xcalloc(1, 4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (push_verbosely)
fprintf(stderr, "Getting pack list\n");
@@ -1030,7 +1029,7 @@ static int fetch_indices(void)
if (start_active_slot(slot)) {
run_active_slot(slot);
if (results.curl_result != CURLE_OK) {
free(buffer.buffer);
strbuf_release(&buffer);
free(url);
if (results.http_code == 404)
return 0;
@@ -1038,18 +1037,18 @@ static int fetch_indices(void)
return error("%s", curl_errorstr);
}
} else {
free(buffer.buffer);
strbuf_release(&buffer);
free(url);
return error("Unable to start request");
}
free(url);
data = buffer.buffer;
while (i < buffer.posn) {
data = buffer.buf;
while (i < buffer.len) {
switch (data[i]) {
case 'P':
i++;
if (i + 52 < buffer.posn &&
if (i + 52 < buffer.len &&
!prefixcmp(data + i, " pack-") &&
!prefixcmp(data + i + 46, ".pack\n")) {
get_sha1_hex(data + i + 6, sha1);
@@ -1064,89 +1063,10 @@ static int fetch_indices(void)
i++;
}
free(buffer.buffer);
strbuf_release(&buffer);
return 0;
}
static inline int needs_quote(int ch)
{
if (((ch >= 'A') && (ch <= 'Z'))
|| ((ch >= 'a') && (ch <= 'z'))
|| ((ch >= '0') && (ch <= '9'))
|| (ch == '/')
|| (ch == '-')
|| (ch == '.'))
return 0;
return 1;
}
static inline int hex(int v)
{
if (v < 10) return '0' + v;
else return 'A' + v - 10;
}
static char *quote_ref_url(const char *base, const char *ref)
{
const char *cp;
char *dp, *qref;
int len, baselen, ch;
baselen = strlen(base);
len = baselen + 1;
for (cp = ref; (ch = *cp) != 0; cp++, len++)
if (needs_quote(ch))
len += 2; /* extra two hex plus replacement % */
qref = xmalloc(len);
memcpy(qref, base, baselen);
for (cp = ref, dp = qref + baselen; (ch = *cp) != 0; cp++) {
if (needs_quote(ch)) {
*dp++ = '%';
*dp++ = hex((ch >> 4) & 0xF);
*dp++ = hex(ch & 0xF);
}
else
*dp++ = ch;
}
*dp = 0;
return qref;
}
int fetch_ref(char *ref, unsigned char *sha1)
{
char *url;
char hex[42];
struct buffer buffer;
char *base = remote->url;
struct active_request_slot *slot;
struct slot_results results;
buffer.size = 41;
buffer.posn = 0;
buffer.buffer = hex;
hex[41] = '\0';
url = quote_ref_url(base, ref);
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
if (start_active_slot(slot)) {
run_active_slot(slot);
if (results.curl_result != CURLE_OK)
return error("Couldn't get %s for %s\n%s",
url, ref, curl_errorstr);
} else {
return error("Unable to start request");
}
hex[40] = '\0';
get_sha1_hex(hex, sha1);
return 0;
}
static void one_remote_object(const char *hex)
{
unsigned char sha1[20];
@@ -1267,10 +1187,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
{
struct active_request_slot *slot;
struct slot_results results;
struct buffer out_buffer;
struct buffer in_buffer;
char *out_data;
char *in_data;
struct buffer out_buffer = { STRBUF_INIT, 0 };
struct strbuf in_buffer = STRBUF_INIT;
char *url;
char *ep;
char timeout_header[25];
@@ -1310,16 +1228,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
ep = strchr(ep + 1, '/');
}
out_buffer.size = strlen(LOCK_REQUEST) + strlen(git_default_email) - 2;
out_data = xmalloc(out_buffer.size + 1);
snprintf(out_data, out_buffer.size + 1, LOCK_REQUEST, git_default_email);
out_buffer.posn = 0;
out_buffer.buffer = out_data;
in_buffer.size = 4096;
in_data = xmalloc(in_buffer.size);
in_buffer.posn = 0;
in_buffer.buffer = in_data;
strbuf_addf(&out_buffer.buf, LOCK_REQUEST, git_default_email);
sprintf(timeout_header, "Timeout: Second-%ld", timeout);
dav_headers = curl_slist_append(dav_headers, timeout_header);
@@ -1328,7 +1237,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
@@ -1354,8 +1263,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
XML_SetElementHandler(parser, xml_start_tag,
xml_end_tag);
XML_SetCharacterDataHandler(parser, xml_cdata);
result = XML_Parse(parser, in_buffer.buffer,
in_buffer.posn, 1);
result = XML_Parse(parser, in_buffer.buf,
in_buffer.len, 1);
free(ctx.name);
if (result != XML_STATUS_OK) {
fprintf(stderr, "XML error: %s\n",
@@ -1370,8 +1279,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
}
curl_slist_free_all(dav_headers);
free(out_data);
free(in_data);
strbuf_release(&out_buffer.buf);
strbuf_release(&in_buffer);
if (lock->token == NULL || lock->timeout <= 0) {
if (lock->token != NULL)
@@ -1522,10 +1431,8 @@ static void remote_ls(const char *path, int flags,
char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
struct active_request_slot *slot;
struct slot_results results;
struct buffer in_buffer;
struct buffer out_buffer;
char *in_data;
char *out_data;
struct strbuf in_buffer = STRBUF_INIT;
struct buffer out_buffer = { STRBUF_INIT, 0 };
struct curl_slist *dav_headers = NULL;
struct xml_ctx ctx;
struct remote_ls_ctx ls;
@@ -1539,16 +1446,7 @@ static void remote_ls(const char *path, int flags,
sprintf(url, "%s%s", remote->url, path);
out_buffer.size = strlen(PROPFIND_ALL_REQUEST);
out_data = xmalloc(out_buffer.size + 1);
snprintf(out_data, out_buffer.size + 1, PROPFIND_ALL_REQUEST);
out_buffer.posn = 0;
out_buffer.buffer = out_data;
in_buffer.size = 4096;
in_data = xmalloc(in_buffer.size);
in_buffer.posn = 0;
in_buffer.buffer = in_data;
strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
dav_headers = curl_slist_append(dav_headers, "Depth: 1");
dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
@@ -1556,7 +1454,7 @@ static void remote_ls(const char *path, int flags,
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
@@ -1579,8 +1477,8 @@ static void remote_ls(const char *path, int flags,
XML_SetElementHandler(parser, xml_start_tag,
xml_end_tag);
XML_SetCharacterDataHandler(parser, xml_cdata);
result = XML_Parse(parser, in_buffer.buffer,
in_buffer.posn, 1);
result = XML_Parse(parser, in_buffer.buf,
in_buffer.len, 1);
free(ctx.name);
if (result != XML_STATUS_OK) {
@@ -1596,8 +1494,8 @@ static void remote_ls(const char *path, int flags,
free(ls.path);
free(url);
free(out_data);
free(in_buffer.buffer);
strbuf_release(&out_buffer.buf);
strbuf_release(&in_buffer);
curl_slist_free_all(dav_headers);
}
@@ -1618,27 +1516,13 @@ static int locking_available(void)
{
struct active_request_slot *slot;
struct slot_results results;
struct buffer in_buffer;
struct buffer out_buffer;
char *in_data;
char *out_data;
struct strbuf in_buffer = STRBUF_INIT;
struct buffer out_buffer = { STRBUF_INIT, 0 };
struct curl_slist *dav_headers = NULL;
struct xml_ctx ctx;
int lock_flags = 0;
out_buffer.size =
strlen(PROPFIND_SUPPORTEDLOCK_REQUEST) +
strlen(remote->url) - 2;
out_data = xmalloc(out_buffer.size + 1);
snprintf(out_data, out_buffer.size + 1,
PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url);
out_buffer.posn = 0;
out_buffer.buffer = out_data;
in_buffer.size = 4096;
in_data = xmalloc(in_buffer.size);
in_buffer.posn = 0;
in_buffer.buffer = in_data;
strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url);
dav_headers = curl_slist_append(dav_headers, "Depth: 0");
dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
@@ -1646,7 +1530,7 @@ static int locking_available(void)
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
@@ -1668,8 +1552,8 @@ static int locking_available(void)
XML_SetUserData(parser, &ctx);
XML_SetElementHandler(parser, xml_start_tag,
xml_end_tag);
result = XML_Parse(parser, in_buffer.buffer,
in_buffer.posn, 1);
result = XML_Parse(parser, in_buffer.buf,
in_buffer.len, 1);
free(ctx.name);
if (result != XML_STATUS_OK) {
@@ -1684,8 +1568,8 @@ static int locking_available(void)
fprintf(stderr, "Unable to start PROPFIND request\n");
}
free(out_data);
free(in_buffer.buffer);
strbuf_release(&out_buffer.buf);
strbuf_release(&in_buffer);
curl_slist_free_all(dav_headers);
return lock_flags;
@@ -1803,30 +1687,20 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
{
struct active_request_slot *slot;
struct slot_results results;
char *out_data;
char *if_header;
struct buffer out_buffer;
struct buffer out_buffer = { STRBUF_INIT, 0 };
struct curl_slist *dav_headers = NULL;
int i;
if_header = xmalloc(strlen(lock->token) + 25);
sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
dav_headers = curl_slist_append(dav_headers, if_header);
out_buffer.size = 41;
out_data = xmalloc(out_buffer.size + 1);
i = snprintf(out_data, out_buffer.size + 1, "%s\n", sha1_to_hex(sha1));
if (i != out_buffer.size) {
fprintf(stderr, "Unable to initialize PUT request body\n");
return 0;
}
out_buffer.posn = 0;
out_buffer.buffer = out_data;
strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
@@ -1837,7 +1711,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
if (start_active_slot(slot)) {
run_active_slot(slot);
free(out_data);
strbuf_release(&out_buffer.buf);
free(if_header);
if (results.curl_result != CURLE_OK) {
fprintf(stderr,
@@ -1847,7 +1721,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
return 0;
}
} else {
free(out_data);
strbuf_release(&out_buffer.buf);
free(if_header);
fprintf(stderr, "Unable to start PUT request\n");
return 0;
@@ -1878,7 +1752,8 @@ static void one_remote_ref(char *refname)
struct object *obj;
int len = strlen(refname) + 1;
if (fetch_ref(refname, remote_sha1) != 0) {
if (http_fetch_ref(remote->url, refname + 5 /* "refs/" */,
remote_sha1) != 0) {
fprintf(stderr,
"Unable to fetch ref %s from %s\n",
refname, remote->url);
@@ -2004,13 +1879,14 @@ static void mark_edges_uninteresting(struct commit_list *list)
static void add_remote_info_ref(struct remote_ls_ctx *ls)
{
struct buffer *buf = (struct buffer *)ls->userData;
struct strbuf *buf = (struct strbuf *)ls->userData;
unsigned char remote_sha1[20];
struct object *o;
int len;
char *ref_info;
if (fetch_ref(ls->dentry_name, remote_sha1) != 0) {
if (http_fetch_ref(remote->url, ls->dentry_name + 5 /* "refs/" */,
remote_sha1) != 0) {
fprintf(stderr,
"Unable to fetch ref %s from %s\n",
ls->dentry_name, remote->url);
@@ -2049,17 +1925,14 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
static void update_remote_info_refs(struct remote_lock *lock)
{
struct buffer buffer;
struct buffer buffer = { STRBUF_INIT, 0 };
struct active_request_slot *slot;
struct slot_results results;
char *if_header;
struct curl_slist *dav_headers = NULL;
buffer.buffer = xcalloc(1, 4096);
buffer.size = 4096;
buffer.posn = 0;
remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
add_remote_info_ref, &buffer);
add_remote_info_ref, &buffer.buf);
if (!aborted) {
if_header = xmalloc(strlen(lock->token) + 25);
sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
@@ -2068,7 +1941,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.posn);
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
@@ -2077,8 +1950,6 @@ static void update_remote_info_refs(struct remote_lock *lock)
curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
buffer.posn = 0;
if (start_active_slot(slot)) {
run_active_slot(slot);
if (results.curl_result != CURLE_OK) {
@@ -2089,7 +1960,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
}
free(if_header);
}
free(buffer.buffer);
strbuf_release(&buffer.buf);
}
static int remote_exists(const char *path)
@@ -2097,43 +1968,43 @@ static int remote_exists(const char *path)
char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
struct active_request_slot *slot;
struct slot_results results;
int ret = -1;
sprintf(url, "%s%s", remote->url, path);
slot = get_active_slot();
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
if (start_active_slot(slot)) {
if (start_active_slot(slot)) {
run_active_slot(slot);
free(url);
if (results.http_code == 404)
return 0;
ret = 0;
else if (results.curl_result == CURLE_OK)
return 1;
ret = 1;
else
fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code);
} else {
free(url);
fprintf(stderr, "Unable to start HEAD request\n");
}
return -1;
free(url);
return ret;
}
static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
{
char *url;
struct buffer buffer;
struct strbuf buffer = STRBUF_INIT;
struct active_request_slot *slot;
struct slot_results results;
url = xmalloc(strlen(remote->url) + strlen(path) + 1);
sprintf(url, "%s%s", remote->url, path);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = xmalloc(buffer.size);
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
@@ -2156,17 +2027,17 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
*symref = NULL;
hashclr(sha1);
if (buffer.posn == 0)
if (buffer.len == 0)
return;
/* If it's a symref, set the refname; otherwise try for a sha1 */
if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
*symref = xmemdupz((char *)buffer.buffer + 5, buffer.posn - 6);
if (!prefixcmp((char *)buffer.buf, "ref: ")) {
*symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
} else {
get_sha1_hex(buffer.buffer, sha1);
get_sha1_hex(buffer.buf, sha1);
}
free(buffer.buffer);
strbuf_release(&buffer);
}
static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
@@ -2354,11 +2225,6 @@ int main(int argc, char **argv)
http_init();
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
default_headers = curl_slist_append(default_headers, "Range:");
default_headers = curl_slist_append(default_headers, "Destination:");
default_headers = curl_slist_append(default_headers, "If:");
default_headers = curl_slist_append(default_headers,
"Pragma: no-cache");
/* Verify DAV compliance/lock support */
if (!locking_available()) {
@@ -2538,7 +2404,6 @@ int main(int argc, char **argv)
free(remote);
curl_slist_free_all(no_pragma_header);
curl_slist_free_all(default_headers);
http_cleanup();

View File

@@ -48,7 +48,7 @@ struct alternates_request {
struct walker *walker;
const char *base;
char *url;
struct buffer *buffer;
struct strbuf *buffer;
struct active_request_slot *slot;
int http_specific;
};
@@ -90,19 +90,6 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
return size;
}
static int missing__target(int code, int result)
{
return /* file:// URL -- do we ever use one??? */
(result == CURLE_FILE_COULDNT_READ_FILE) ||
/* http:// and https:// URL */
(code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
/* ftp:// URL */
(code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
;
}
#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
static void fetch_alternates(struct walker *walker, const char *base);
static void process_object_response(void *callback_data);
@@ -475,7 +462,7 @@ static void process_alternates_response(void *callback_data)
if (alt_req->http_specific) {
if (slot->curl_result != CURLE_OK ||
!alt_req->buffer->posn) {
!alt_req->buffer->len) {
/* Try reusing the slot to get non-http alternates */
alt_req->http_specific = 0;
@@ -503,12 +490,12 @@ static void process_alternates_response(void *callback_data)
}
fwrite_buffer(&null_byte, 1, 1, alt_req->buffer);
alt_req->buffer->posn--;
data = alt_req->buffer->buffer;
alt_req->buffer->len--;
data = alt_req->buffer->buf;
while (i < alt_req->buffer->posn) {
while (i < alt_req->buffer->len) {
int posn = i;
while (posn < alt_req->buffer->posn && data[posn] != '\n')
while (posn < alt_req->buffer->len && data[posn] != '\n')
posn++;
if (data[posn] == '\n') {
int okay = 0;
@@ -596,9 +583,8 @@ static void process_alternates_response(void *callback_data)
static void fetch_alternates(struct walker *walker, const char *base)
{
struct buffer buffer;
struct strbuf buffer = STRBUF_INIT;
char *url;
char *data;
struct active_request_slot *slot;
struct alternates_request alt_req;
struct walker_data *cdata = walker->data;
@@ -619,11 +605,6 @@ static void fetch_alternates(struct walker *walker, const char *base)
/* Start the fetch */
cdata->got_alternates = 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (walker->get_verbosely)
fprintf(stderr, "Getting alternates list for %s\n", base);
@@ -652,7 +633,7 @@ static void fetch_alternates(struct walker *walker, const char *base)
else
cdata->got_alternates = -1;
free(data);
strbuf_release(&buffer);
free(url);
}
@@ -660,9 +641,10 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
{
unsigned char sha1[20];
char *url;
struct buffer buffer;
struct strbuf buffer = STRBUF_INIT;
char *data;
int i = 0;
int ret = 0;
struct active_request_slot *slot;
struct slot_results results;
@@ -670,11 +652,6 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
if (repo->got_indices)
return 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (walker->get_verbosely)
fprintf(stderr, "Getting pack list for %s\n", repo->base);
@@ -692,26 +669,25 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
if (results.curl_result != CURLE_OK) {
if (missing_target(&results)) {
repo->got_indices = 1;
free(buffer.buffer);
return 0;
goto cleanup;
} else {
repo->got_indices = 0;
free(buffer.buffer);
return error("%s", curl_errorstr);
ret = error("%s", curl_errorstr);
goto cleanup;
}
}
} else {
repo->got_indices = 0;
free(buffer.buffer);
return error("Unable to start request");
ret = error("Unable to start request");
goto cleanup;
}
data = buffer.buffer;
while (i < buffer.posn) {
data = buffer.buf;
while (i < buffer.len) {
switch (data[i]) {
case 'P':
i++;
if (i + 52 <= buffer.posn &&
if (i + 52 <= buffer.len &&
!prefixcmp(data + i, " pack-") &&
!prefixcmp(data + i + 46, ".pack\n")) {
get_sha1_hex(data + i + 6, sha1);
@@ -720,15 +696,17 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
break;
}
default:
while (i < buffer.posn && data[i] != '\n')
while (i < buffer.len && data[i] != '\n')
i++;
}
i++;
}
free(buffer.buffer);
repo->got_indices = 1;
return 0;
cleanup:
strbuf_release(&buffer);
free(url);
return ret;
}
static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
@@ -910,85 +888,10 @@ static int fetch(struct walker *walker, unsigned char *sha1)
data->alt->base);
}
static inline int needs_quote(int ch)
{
if (((ch >= 'A') && (ch <= 'Z'))
|| ((ch >= 'a') && (ch <= 'z'))
|| ((ch >= '0') && (ch <= '9'))
|| (ch == '/')
|| (ch == '-')
|| (ch == '.'))
return 0;
return 1;
}
static inline int hex(int v)
{
if (v < 10) return '0' + v;
else return 'A' + v - 10;
}
static char *quote_ref_url(const char *base, const char *ref)
{
const char *cp;
char *dp, *qref;
int len, baselen, ch;
baselen = strlen(base);
len = baselen + 7; /* "/refs/" + NUL */
for (cp = ref; (ch = *cp) != 0; cp++, len++)
if (needs_quote(ch))
len += 2; /* extra two hex plus replacement % */
qref = xmalloc(len);
memcpy(qref, base, baselen);
memcpy(qref + baselen, "/refs/", 6);
for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) {
if (needs_quote(ch)) {
*dp++ = '%';
*dp++ = hex((ch >> 4) & 0xF);
*dp++ = hex(ch & 0xF);
}
else
*dp++ = ch;
}
*dp = 0;
return qref;
}
static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1)
{
char *url;
char hex[42];
struct buffer buffer;
struct walker_data *data = walker->data;
const char *base = data->alt->base;
struct active_request_slot *slot;
struct slot_results results;
buffer.size = 41;
buffer.posn = 0;
buffer.buffer = hex;
hex[41] = '\0';
url = quote_ref_url(base, ref);
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
if (start_active_slot(slot)) {
run_active_slot(slot);
if (results.curl_result != CURLE_OK)
return error("Couldn't get %s for %s\n%s",
url, ref, curl_errorstr);
} else {
return error("Unable to start request");
}
hex[40] = '\0';
get_sha1_hex(hex, sha1);
return 0;
return http_fetch_ref(data->alt->base, ref, sha1);
}
static void cleanup(struct walker *walker)

117
http.c
View File

@@ -34,31 +34,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
struct buffer *buffer)
{
size_t size = eltsize * nmemb;
if (size > buffer->size - buffer->posn)
size = buffer->size - buffer->posn;
memcpy(ptr, (char *) buffer->buffer + buffer->posn, size);
if (size > buffer->buf.len - buffer->posn)
size = buffer->buf.len - buffer->posn;
memcpy(ptr, buffer->buf.buf + buffer->posn, size);
buffer->posn += size;
return size;
}
size_t fwrite_buffer(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer)
size_t nmemb, struct strbuf *buffer)
{
size_t size = eltsize * nmemb;
if (size > buffer->size - buffer->posn) {
buffer->size = buffer->size * 3 / 2;
if (buffer->size < buffer->posn + size)
buffer->size = buffer->posn + size;
buffer->buffer = xrealloc(buffer->buffer, buffer->size);
}
memcpy((char *) buffer->buffer + buffer->posn, ptr, size);
buffer->posn += size;
strbuf_add(buffer, ptr, size);
data_received++;
return size;
}
size_t fwrite_null(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer)
size_t nmemb, struct strbuf *buffer)
{
data_received++;
return eltsize * nmemb;
@@ -370,7 +364,6 @@ struct active_request_slot *get_active_slot(void)
slot->finished = NULL;
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
@@ -508,8 +501,8 @@ void run_active_slot(struct active_request_slot *slot)
static void closedown_active_slot(struct active_request_slot *slot)
{
active_requests--;
slot->in_use = 0;
active_requests--;
slot->in_use = 0;
}
void release_active_slot(struct active_request_slot *slot)
@@ -530,7 +523,7 @@ void release_active_slot(struct active_request_slot *slot)
static void finish_active_slot(struct active_request_slot *slot)
{
closedown_active_slot(slot);
curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
if (slot->finished != NULL)
(*slot->finished) = 1;
@@ -541,10 +534,10 @@ static void finish_active_slot(struct active_request_slot *slot)
slot->results->http_code = slot->http_code;
}
/* Run callback if appropriate */
if (slot->callback_func != NULL) {
slot->callback_func(slot->callback_data);
}
/* Run callback if appropriate */
if (slot->callback_func != NULL) {
slot->callback_func(slot->callback_data);
}
}
void finish_all_active_slots(void)
@@ -559,3 +552,85 @@ void finish_all_active_slots(void)
slot = slot->next;
}
}
static inline int needs_quote(int ch)
{
if (((ch >= 'A') && (ch <= 'Z'))
|| ((ch >= 'a') && (ch <= 'z'))
|| ((ch >= '0') && (ch <= '9'))
|| (ch == '/')
|| (ch == '-')
|| (ch == '.'))
return 0;
return 1;
}
static inline int hex(int v)
{
if (v < 10) return '0' + v;
else return 'A' + v - 10;
}
static char *quote_ref_url(const char *base, const char *ref)
{
const char *cp;
char *dp, *qref;
int len, baselen, ch;
baselen = strlen(base);
len = baselen + 7; /* "/refs/" + NUL */
for (cp = ref; (ch = *cp) != 0; cp++, len++)
if (needs_quote(ch))
len += 2; /* extra two hex plus replacement % */
qref = xmalloc(len);
memcpy(qref, base, baselen);
memcpy(qref + baselen, "/refs/", 6);
for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) {
if (needs_quote(ch)) {
*dp++ = '%';
*dp++ = hex((ch >> 4) & 0xF);
*dp++ = hex(ch & 0xF);
}
else
*dp++ = ch;
}
*dp = 0;
return qref;
}
int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1)
{
char *url;
struct strbuf buffer = STRBUF_INIT;
struct active_request_slot *slot;
struct slot_results results;
int ret;
url = quote_ref_url(base, ref);
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
if (start_active_slot(slot)) {
run_active_slot(slot);
if (results.curl_result == CURLE_OK) {
strbuf_rtrim(&buffer);
if (buffer.len == 40)
ret = get_sha1_hex(buffer.buf, sha1);
else
ret = 1;
} else {
ret = error("Couldn't get %s for %s\n%s",
url, ref, curl_errorstr);
}
} else {
ret = error("Unable to start request");
}
strbuf_release(&buffer);
free(url);
return ret;
}

26
http.h
View File

@@ -6,6 +6,8 @@
#include <curl/curl.h>
#include <curl/easy.h>
#include "strbuf.h"
#if LIBCURL_VERSION_NUM >= 0x071000
#define USE_CURL_MULTI
#define DEFAULT_MAX_REQUESTS 5
@@ -48,18 +50,17 @@ struct active_request_slot
struct buffer
{
size_t posn;
size_t size;
void *buffer;
struct strbuf buf;
size_t posn;
};
/* Curl request read/write callbacks */
extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
struct buffer *buffer);
extern size_t fwrite_buffer(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer);
size_t nmemb, struct strbuf *buffer);
extern size_t fwrite_null(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer);
size_t nmemb, struct strbuf *buffer);
/* Slot lifecycle functions */
extern struct active_request_slot *get_active_slot(void);
@@ -82,4 +83,19 @@ extern int active_requests;
extern char curl_errorstr[CURL_ERROR_SIZE];
static inline int missing__target(int code, int result)
{
return /* file:// URL -- do we ever use one??? */
(result == CURLE_FILE_COULDNT_READ_FILE) ||
/* http:// and https:// URL */
(code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
/* ftp:// URL */
(code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
;
}
#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
extern int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1);
#endif /* HTTP_H */

View File

@@ -71,7 +71,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
res->size = 0;
ecb.priv = res;
return xdl_diff(f1, f2, &xpp, &xecfg, &ecb);
return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
}
void *merge_file(struct blob *base, struct blob *our, struct blob *their, unsigned long *size)

View File

@@ -549,6 +549,10 @@ static void update_file_flags(const unsigned char *sha,
void *buf;
unsigned long size;
if (S_ISGITLINK(mode))
die("cannot read object %s '%s': It is a submodule!",
sha1_to_hex(sha), path);
buf = read_sha1_file(sha, &type, &size);
if (!buf)
die("cannot read object %s '%s'", sha1_to_hex(sha), path);
@@ -1463,10 +1467,13 @@ static int process_entry(const char *path, struct stage_data *entry,
mfi = merge_file(&o, &a, &b,
branch1, branch2);
clean_merge = mfi.clean;
if (mfi.clean)
update_file(1, mfi.sha, mfi.mode, path);
else if (S_ISGITLINK(mfi.mode))
output(1, "CONFLICT (submodule): Merge conflict in %s "
"- needs %s", path, sha1_to_hex(b.sha1));
else {
clean_merge = 0;
output(1, "CONFLICT (%s): Merge conflict in %s",
reason, path);

View File

@@ -119,7 +119,7 @@ static void show_diff(struct merge_list *entry)
if (!dst.ptr)
size = 0;
dst.size = size;
xdl_diff(&src, &dst, &xpp, &xecfg, &ecb);
xdi_diff(&src, &dst, &xpp, &xecfg, &ecb);
free(src.ptr);
free(dst.ptr);
}

View File

@@ -220,11 +220,11 @@ static int handle_config(const char *key, const char *value)
if (!prefixcmp(key, "branch.")) {
name = key + 7;
subkey = strrchr(name, '.');
branch = make_branch(name, subkey - name);
if (!subkey)
return 0;
if (!value)
return 0;
branch = make_branch(name, subkey - name);
if (!strcmp(subkey, ".remote")) {
branch->remote_name = xstrdup(value);
if (branch == current_branch)

View File

@@ -21,8 +21,8 @@ compare_diff_raw_z () {
# Also we do not check SHA1 hash generation in this test, which
# is a job for t0000-basic.sh
tr '\0' '\012' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
tr '\0' '\012' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
tr '\000' '\012' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
tr '\000' '\012' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
}

View File

@@ -5,7 +5,7 @@ test_description='CRLF conversion'
. ./test-lib.sh
q_to_nul () {
tr Q '\0'
tr Q '\000'
}
append_cr () {

View File

@@ -591,12 +591,12 @@ Qsection.sub=section.val4
Qsection.sub=section.val5Q
EOF
git config --null --list | tr '[\000]' 'Q' > result
git config --null --list | tr '\000' 'Q' > result
echo >>result
test_expect_success '--null --list' 'cmp result expect'
git config --null --get-regexp 'val[0-9]' | tr '[\000]' 'Q' > result
git config --null --get-regexp 'val[0-9]' | tr '\000' 'Q' > result
echo >>result
test_expect_success '--null --get-regexp' 'cmp result expect'

View File

@@ -54,7 +54,7 @@ echo 'just space
no-funny
tabs ," (dq) and spaces' >expected
test_expect_success 'git ls-files -z with-funny' \
'git ls-files -z | tr \\0 \\012 >current &&
'git ls-files -z | tr \\000 \\012 >current &&
git diff expected current'
t1=`git write-tree`
@@ -83,11 +83,11 @@ test_expect_success 'git diff-tree with-funny' \
echo 'A
tabs ," (dq) and spaces' >expected
test_expect_success 'git diff-index -z with-funny' \
'git diff-index -z --name-status $t0 | tr \\0 \\012 >current &&
'git diff-index -z --name-status $t0 | tr \\000 \\012 >current &&
git diff expected current'
test_expect_success 'git diff-tree -z with-funny' \
'git diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current &&
'git diff-tree -z --name-status $t0 $t1 | tr \\000 \\012 >current &&
git diff expected current'
cat > expected <<\EOF

View File

@@ -184,6 +184,12 @@ test_expect_success 'retain authorship when squashing' '
git show HEAD | grep "^Author: Twerp Snog"
'
test_expect_success '-p handles "no changes" gracefully' '
HEAD=$(git rev-parse HEAD) &&
git rebase -i -p HEAD^ &&
test $HEAD = $(git rev-parse HEAD)
'
test_expect_success 'preserve merges with -p' '
git checkout -b to-be-preserved master^ &&
: > unrelated-file &&

View File

@@ -117,13 +117,213 @@ EOF
git diff -b > out
test_expect_success 'another test, with -b' 'git diff expect out'
test_expect_success 'check mixed spaces and tabs in indent' '
# This is indented with SP HT SP.
echo " foo();" > x &&
git diff --check | grep "space before tab"
git diff --check | grep "space before tab in indent"
'
test_expect_success 'check mixed tabs and spaces in indent' '
# This is indented with HT SP HT.
echo " foo();" > x &&
git diff --check | grep "space before tab in indent"
'
test_expect_success 'check with no whitespace errors' '
git commit -m "snapshot" &&
echo "foo();" > x &&
git diff --check
'
test_expect_success 'check with trailing whitespace' '
echo "foo(); " > x &&
! git diff --check
'
test_expect_success 'check with space before tab in indent' '
# indent has space followed by hard tab
echo " foo();" > x &&
! git diff --check
'
test_expect_success '--check and --exit-code are not exclusive' '
git checkout x &&
git diff --check --exit-code
'
test_expect_success '--check and --quiet are not exclusive' '
git diff --check --quiet
'
test_expect_success 'check staged with no whitespace errors' '
echo "foo();" > x &&
git add x &&
git diff --cached --check
'
test_expect_success 'check staged with trailing whitespace' '
echo "foo(); " > x &&
git add x &&
! git diff --cached --check
'
test_expect_success 'check staged with space before tab in indent' '
# indent has space followed by hard tab
echo " foo();" > x &&
git add x &&
! git diff --cached --check
'
test_expect_success 'check with no whitespace errors (diff-index)' '
echo "foo();" > x &&
git add x &&
git diff-index --check HEAD
'
test_expect_success 'check with trailing whitespace (diff-index)' '
echo "foo(); " > x &&
git add x &&
! git diff-index --check HEAD
'
test_expect_success 'check with space before tab in indent (diff-index)' '
# indent has space followed by hard tab
echo " foo();" > x &&
git add x &&
! git diff-index --check HEAD
'
test_expect_success 'check staged with no whitespace errors (diff-index)' '
echo "foo();" > x &&
git add x &&
git diff-index --cached --check HEAD
'
test_expect_success 'check staged with trailing whitespace (diff-index)' '
echo "foo(); " > x &&
git add x &&
! git diff-index --cached --check HEAD
'
test_expect_success 'check staged with space before tab in indent (diff-index)' '
# indent has space followed by hard tab
echo " foo();" > x &&
git add x &&
! git diff-index --cached --check HEAD
'
test_expect_success 'check with no whitespace errors (diff-tree)' '
echo "foo();" > x &&
git commit -m "new commit" x &&
git diff-tree --check HEAD^ HEAD
'
test_expect_success 'check with trailing whitespace (diff-tree)' '
echo "foo(); " > x &&
git commit -m "another commit" x &&
! git diff-tree --check HEAD^ HEAD
'
test_expect_success 'check with space before tab in indent (diff-tree)' '
# indent has space followed by hard tab
echo " foo();" > x &&
git commit -m "yet another" x &&
! git diff-tree --check HEAD^ HEAD
'
test_expect_success 'check trailing whitespace (trailing-space: off)' '
git config core.whitespace "-trailing-space" &&
echo "foo (); " > x &&
git diff --check
'
test_expect_success 'check trailing whitespace (trailing-space: on)' '
git config core.whitespace "trailing-space" &&
echo "foo (); " > x &&
! git diff --check
'
test_expect_success 'check space before tab in indent (space-before-tab: off)' '
# indent contains space followed by HT
git config core.whitespace "-space-before-tab" &&
echo " foo ();" > x &&
git diff --check
'
test_expect_success 'check space before tab in indent (space-before-tab: on)' '
# indent contains space followed by HT
git config core.whitespace "space-before-tab" &&
echo " foo (); " > x &&
! git diff --check
'
test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' '
git config core.whitespace "-indent-with-non-tab"
echo " foo ();" > x &&
git diff --check
'
test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' '
git config core.whitespace "indent-with-non-tab" &&
echo " foo ();" > x &&
! git diff --check
'
test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' '
git config core.whitespace "indent-with-non-tab" &&
echo " foo ();" > x &&
! git diff --check
'
test_done

View File

@@ -76,4 +76,33 @@ test_expect_success 'git diff-index --cached HEAD' '
}
'
test_expect_success '--check --exit-code returns 0 for no difference' '
git diff --check --exit-code
'
test_expect_success '--check --exit-code returns 1 for a clean difference' '
echo "good" > a &&
git diff --check --exit-code
test $? = 1
'
test_expect_success '--check --exit-code returns 3 for a dirty difference' '
echo "bad " >> a &&
git diff --check --exit-code
test $? = 3
'
test_expect_success '--check with --no-pager returns 2 for dirty difference' '
git --no-pager diff --check
test $? = 2
'
test_done

View File

@@ -99,7 +99,7 @@ test_expect_success 'no diff with -diff' '
git diff | grep Binary
'
echo NULZbetweenZwords | tr Z '\0' > file
echo NULZbetweenZwords | tr Z '\000' > file
test_expect_success 'force diff with "diff"' '
echo >.gitattributes "file diff" &&

69
t/t4024-diff-optimize-common.sh Executable file
View File

@@ -0,0 +1,69 @@
#!/bin/sh
test_description='common tail optimization'
. ./test-lib.sh
z=zzzzzzzz ;# 8
z="$z$z$z$z$z$z$z$z" ;# 64
z="$z$z$z$z$z$z$z$z" ;# 512
z="$z$z$z$z" ;# 2048
z2047=$(expr "$z" : '.\(.*\)') ; #2047
test_expect_success setup '
echo "a$z2047" >file-a &&
echo "b" >file-b &&
echo "$z2047" >>file-b &&
echo "c$z2047" | tr -d "\012" >file-c &&
echo "d" >file-d &&
echo "$z2047" | tr -d "\012" >>file-d &&
git add file-a file-b file-c file-d &&
echo "A$z2047" >file-a &&
echo "B" >file-b &&
echo "$z2047" >>file-b &&
echo "C$z2047" | tr -d "\012" >file-c &&
echo "D" >file-d &&
echo "$z2047" | tr -d "\012" >>file-d
'
cat >expect <<\EOF
diff --git a/file-a b/file-a
--- a/file-a
+++ b/file-a
@@ -1 +1 @@
-aZ
+AZ
diff --git a/file-b b/file-b
--- a/file-b
+++ b/file-b
@@ -1 +1 @@
-b
+B
diff --git a/file-c b/file-c
--- a/file-c
+++ b/file-c
@@ -1 +1 @@
-cZ
\ No newline at end of file
+CZ
\ No newline at end of file
diff --git a/file-d b/file-d
--- a/file-d
+++ b/file-d
@@ -1 +1 @@
-d
+D
EOF
test_expect_success 'diff -U0' '
git diff -U0 | sed -e "/^index/d" -e "s/$z2047/Z/g" >actual &&
diff -u expect actual
'
test_done

View File

@@ -24,10 +24,10 @@ git update-index --add --remove file1 file2 file4
git-commit -m 'Initial Version' 2>/dev/null
git-checkout -b binary
tr 'x' '\0' <file1 >file3
tr 'x' '\000' <file1 >file3
cat file3 >file4
git add file2
tr '\0' 'v' <file3 >file1
tr '\000' 'v' <file3 >file1
rm -f file2
git update-index --add --remove file1 file2 file3 file4
git-commit -m 'Second Version'

View File

@@ -12,14 +12,14 @@ test_description='git apply in reverse
test_expect_success setup '
for i in a b c d e f g h i j k l m n; do echo $i; done >file1 &&
tr "[ijk]" '\''[\0\1\2]'\'' <file1 >file2 &&
tr "ijk" '\''\000\001\002'\'' <file1 >file2 &&
git add file1 file2 &&
git commit -m initial &&
git tag initial &&
for i in a b c g h i J K L m o n p q; do echo $i; done >file1 &&
tr "[mon]" '\''[\0\1\2]'\'' <file1 >file2 &&
tr "mon" '\''\000\001\002'\'' <file1 >file2 &&
git commit -a -m second &&
git tag second &&

View File

@@ -129,7 +129,7 @@ test_expect_success 'rerere kicked in' "! grep ======= a1"
test_expect_success 'rerere prefers first change' 'git diff a1 expect'
rm $rr/postimage
echo "$sha1 a1" | tr '\012' '\0' > .git/rr-cache/MERGE_RR
echo "$sha1 a1" | tr '\012' '\000' > .git/rr-cache/MERGE_RR
test_expect_success 'rerere clear' 'git rerere clear'

22
t/t5702-clone-options.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/sh
test_description='basic clone options'
. ./test-lib.sh
test_expect_success 'setup' '
mkdir parent &&
(cd parent && git init &&
echo one >file && git add file &&
git commit -m one)
'
test_expect_success 'clone -o' '
git clone -o foo parent clone-o &&
(cd clone-o && git rev-parse --verify refs/remotes/foo/master)
'
test_done

Some files were not shown because too many files have changed in this diff Show More