mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'mingw/master' into work/merge-mingw
Conflicts: help.c
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
1
.mailmap
1
.mailmap
@@ -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>
|
||||
|
||||
1
Documentation/.gitignore
vendored
1
Documentation/.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
*.html
|
||||
*.[1-8]
|
||||
*.made
|
||||
git.info
|
||||
howto-index.txt
|
||||
doc.dep
|
||||
cmds-*.txt
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
-------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
1
Documentation/technical/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
api-index.txt
|
||||
34
Documentation/technical/api-allocation-growing.txt
Normal file
34
Documentation/technical/api-allocation-growing.txt
Normal 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.
|
||||
63
Documentation/technical/api-builtin.txt
Normal file
63
Documentation/technical/api-builtin.txt
Normal 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.
|
||||
6
Documentation/technical/api-decorate.txt
Normal file
6
Documentation/technical/api-decorate.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
decorate API
|
||||
============
|
||||
|
||||
Talk about <decorate.h>
|
||||
|
||||
(Linus)
|
||||
166
Documentation/technical/api-diff.txt
Normal file
166
Documentation/technical/api-diff.txt
Normal 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)
|
||||
76
Documentation/technical/api-directory-listing.txt
Normal file
76
Documentation/technical/api-directory-listing.txt
Normal 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)
|
||||
111
Documentation/technical/api-gitattributes.txt
Normal file
111
Documentation/technical/api-gitattributes.txt
Normal 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)
|
||||
8
Documentation/technical/api-grep.txt
Normal file
8
Documentation/technical/api-grep.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
grep API
|
||||
========
|
||||
|
||||
Talk about <grep.h>, things like:
|
||||
|
||||
* grep_buffer()
|
||||
|
||||
(JC)
|
||||
6
Documentation/technical/api-hash.txt
Normal file
6
Documentation/technical/api-hash.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
hash API
|
||||
========
|
||||
|
||||
Talk about <hash.h>
|
||||
|
||||
(Linus)
|
||||
21
Documentation/technical/api-in-core-index.txt
Normal file
21
Documentation/technical/api-in-core-index.txt
Normal 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)
|
||||
15
Documentation/technical/api-index-skel.txt
Normal file
15
Documentation/technical/api-index-skel.txt
Normal 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
|
||||
28
Documentation/technical/api-index.sh
Executable file
28
Documentation/technical/api-index.sh
Executable 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
|
||||
12
Documentation/technical/api-lockfile.txt
Normal file
12
Documentation/technical/api-lockfile.txt
Normal 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)
|
||||
15
Documentation/technical/api-object-access.txt
Normal file
15
Documentation/technical/api-object-access.txt
Normal 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)
|
||||
6
Documentation/technical/api-parse-options.txt
Normal file
6
Documentation/technical/api-parse-options.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
parse-options API
|
||||
=================
|
||||
|
||||
Talk about <parse-options.h>
|
||||
|
||||
(Pierre)
|
||||
9
Documentation/technical/api-path-list.txt
Normal file
9
Documentation/technical/api-path-list.txt
Normal 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)
|
||||
10
Documentation/technical/api-quote.txt
Normal file
10
Documentation/technical/api-quote.txt
Normal 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)
|
||||
9
Documentation/technical/api-revision-walking.txt
Normal file
9
Documentation/technical/api-revision-walking.txt
Normal 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)
|
||||
10
Documentation/technical/api-run-command.txt
Normal file
10
Documentation/technical/api-run-command.txt
Normal 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)
|
||||
13
Documentation/technical/api-setup.txt
Normal file
13
Documentation/technical/api-setup.txt
Normal 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)
|
||||
6
Documentation/technical/api-strbuf.txt
Normal file
6
Documentation/technical/api-strbuf.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
strbuf API
|
||||
==========
|
||||
|
||||
Talk about <strbuf.h>
|
||||
|
||||
(Pierre, JC)
|
||||
12
Documentation/technical/api-tree-walking.txt
Normal file
12
Documentation/technical/api-tree-walking.txt
Normal 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)
|
||||
7
Documentation/technical/api-xdiff-interface.txt
Normal file
7
Documentation/technical/api-xdiff-interface.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
xdiff interface API
|
||||
===================
|
||||
|
||||
Talk about our calling convention to xdiff library, including
|
||||
xdiff_emit_consume_fn.
|
||||
|
||||
(Dscho, JC)
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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='
|
||||
'
|
||||
|
||||
10
Makefile
10
Makefile
@@ -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"; \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
4
cache.h
4
cache.h
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
91
config.c
91
config.c
@@ -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,
|
||||
|
||||
@@ -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;;
|
||||
|
||||
50
diff-delta.c
50
diff-delta.c
@@ -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
170
diff.c
@@ -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
3
diff.h
@@ -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
3
dir.c
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
13
git-clone.sh
13
git-clone.sh
@@ -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
|
||||
'')
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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}
|
||||
|
||||
100
git-svn.perl
100
git-svn.perl
@@ -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) {
|
||||
|
||||
@@ -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
74
help.c
@@ -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;
|
||||
}
|
||||
|
||||
283
http-push.c
283
http-push.c
@@ -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();
|
||||
|
||||
|
||||
145
http-walker.c
145
http-walker.c
@@ -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
117
http.c
@@ -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
26
http.h
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
2
remote.c
2
remote.c
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ test_description='CRLF conversion'
|
||||
. ./test-lib.sh
|
||||
|
||||
q_to_nul () {
|
||||
tr Q '\0'
|
||||
tr Q '\000'
|
||||
}
|
||||
|
||||
append_cr () {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
69
t/t4024-diff-optimize-common.sh
Executable 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
|
||||
@@ -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'
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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
22
t/t5702-clone-options.sh
Executable 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
Reference in New Issue
Block a user