Merge commit 'mingw/master' into work/1.6.4

This commit is contained in:
Johannes Schindelin
2009-07-29 21:44:37 +02:00
215 changed files with 4526 additions and 1982 deletions

2
.gitattributes vendored
View File

@@ -1,2 +1,2 @@
* whitespace=!indent,trail,space
*.[ch] whitespace
*.[ch] whitespace=indent,trail,space

View File

@@ -84,7 +84,7 @@ endif
#
ifdef ASCIIDOC8
ASCIIDOC_EXTRA += -a asciidoc7compatible
ASCIIDOC_EXTRA += -a asciidoc7compatible -a no-inline-literal
endif
ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff

View File

@@ -0,0 +1,38 @@
GIT v1.6.3.3 Release Notes
==========================
Fixes since v1.6.3.2
--------------------
* "git archive" running on Cygwin can get stuck in an infinite loop.
* "git daemon" did not correctly parse the initial line that carries
virtual host request information.
* "git diff --textconv" leaked memory badly when the textconv filter
errored out.
* The built-in regular expressions to pick function names to put on
hunk header lines for java and objc were very inefficiently written.
* in certain error situations git-fetch (and git-clone) on Windows didn't
detect connection abort and ended up waiting indefinitely.
* import-tars script (in contrib) did not import symbolic links correctly.
* http.c used CURLOPT_SSLKEY even on libcURL version 7.9.2, even though
it was only available starting 7.9.3.
* low-level filelevel merge driver used return value from strdup()
without checking if we ran out of memory.
* "git rebase -i" left stray closing parenthesis in its reflog message.
* "git remote show" did not show all the URLs associated with the named
remote, even though "git remote -v" did. Made them consistent by
making the former show all URLs.
* "whitespace" attribute that is set was meant to detect all errors known
to git, but it told git to ignore trailing carriage-returns.
Includes other documentation fixes.

View File

@@ -0,0 +1,36 @@
GIT v1.6.3.4 Release Notes
==========================
Fixes since v1.6.3.3
--------------------
* "git add --no-ignore-errors" did not override configured
add.ignore-errors configuration.
* "git apply --whitespace=fix" did not fix trailing whitespace on an
incomplete line.
* "git branch" opened too many commit objects unnecessarily.
* "git checkout -f $commit" with a path that is a file (or a symlink) in
the work tree to a commit that has a directory at the path issued an
unnecessary error message.
* "git diff -c/--cc" was very inefficient in coalescing the removed lines
shared between parents.
* "git diff -c/--cc" showed removed lines at the beginning of a file
incorrectly.
* "git remote show nickname" did not honor configured
remote.nickname.uploadpack when inspecting the branches at the remote.
* "git request-pull" when talking to the terminal for a preview
showed some of the output in the pager.
* "git request-pull start nickname [end]" did not honor configured
remote.nickname.uploadpack when it ran git-ls-remote against the remote
repository to learn the current tip of branches.
Includes other documentation updates and minor fixes.

View File

@@ -22,13 +22,6 @@ branch pointed at by its HEAD, gets a large warning. You can choose what
should happen upon such a push by setting the configuration variable
receive.denyDeleteCurrent in the receiving repository.
When the user does not tell "git push" what to push, it has always
pushed matching refs. For some people it is unexpected, and a new
configuration variable push.default has been introduced to allow
changing a different default behaviour. To advertise the new feature,
a big warning is issued if this is not configured and a git push without
arguments is attempted.
Updates since v1.6.3
--------------------
@@ -38,26 +31,67 @@ Updates since v1.6.3
* gitweb Perl style clean-up.
* git-svn updates, including a new --authors-prog option to map author
names by invoking an external program.
names by invoking an external program, 'git svn reset' to unwind
'git svn fetch', support for more than one branches, documenting
of the useful --minimize-url feature, new "git svn gc" command, etc.
(portability)
* We feed iconv with "UTF-8" instead of "utf8"; the former is
understood more widely.
understood more widely. Similarly updated test scripts to use
encoding names more widely understood (e.g. use "ISO8859-1" instead
of "ISO-8859-1").
* Various portability fixes/workarounds for different vintages of
SunOS, IRIX, and Windows.
* Git-over-ssh transport on Windows supports PuTTY plink and TortoisePlink.
(performance)
* Many repeated use of lstat() are optimized out in "checkout" codepath.
* git-status (and underlying git-diff-index --cached) are optimized
to take advantage of cache-tree information in the index.
(usability, bells and whistles)
* "git add --edit" lets users edit the whole patch text to fine-tune what
is added to the index.
* "git log --graph" draws graphs more compactly by using horizonal lines
* "git am" accepts StGIT series file as its input.
* "git bisect skip" skips to a more randomly chosen place in the hope
to avoid testing a commit that is too close to a commit that is
already known to be untestable.
* "git cvsexportcommit" learned -k option to stop CVS keywords expansion
* "git fast-export" learned to handle history simplification more
gracefully.
* "git fast-export" learned an option --tag-of-filtered-object to handle
dangling tags resulting from history simplification more usefully.
* "git grep" learned -p option to show the location of the match using the
same context hunk marker "git diff" uses.
* https transport can optionally be told that the used client
certificate is password protected, in which case it asks the
password only once.
* "git imap-send" is IPv6 aware.
* "git log --graph" draws graphs more compactly by using horizontal lines
when able.
* "git log --decorate" shows shorter refnames by stripping well-known
refs/* prefix.
* "git push $name" honors remote.$name.pushurl if present before
using remote.$name.url. In other words, the URL used for fetching
and pushing can be different.
* "git send-email" understands quoted aliases in .mailrc files (might
have to be backported to 1.6.3.X).
@@ -69,10 +103,17 @@ Updates since v1.6.3
* "add" and "update" subcommands to "git submodule" learned --reference
option to use local clone with references.
* "git submodule update" learned --rebase option to update checked
out submodules by rebasing the local changes.
* "gitweb" can optionally use gravatar to adorn author/committer names.
(developers)
* A major part of the "git bisect" wrapper has moved to C.
* Formatting with the new version of AsciiDoc 8.4.1 is now supported.
Fixes since v1.6.3
------------------
@@ -82,12 +123,25 @@ release, unless otherwise noted.
Here are fixes that this release has, but have not been backported to
v1.6.3.X series.
* "git diff-tree -r -t" used to omit new or removed directories from
the output. df533f3 (diff-tree -r -t: include added/removed
directories in the output, 2009-06-13) may need to be cherry-picked
to backport this fix.
* The way Git.pm sets up a Repository object was not friendly to callers
that chdir around. It now internally records the repository location
as an absolute path when autodetected.
---
exec >/var/tmp/1
echo O=$(git describe master)
O=v1.6.3.1-168-g23807fa
git shortlog --no-merges $O..master ^maint
* Removing a section with "git config --remove-section", when its
section header has a variable definition on the same line, lost
that variable definition.
* "git rebase -p --onto" used to always leave side branches of a merge
intact, even when both branches are subject to rewriting.
* "git repack" used to faithfully follow grafts and considered true
parents recorded in the commit object unreachable from the commit.
After such a repacking, you cannot remove grafts without corrupting
the repository.
* "git send-email" did not detect erroneous loops in alias expansion.

View File

@@ -17,6 +17,7 @@ caret=^
startsb=[
endsb=]
tilde=~
backtick=`
ifdef::backend-docbook[]
[linkgit-inlinemacro]

View File

@@ -49,7 +49,8 @@ There is also a case insensitive alternative `[section.subsection]` syntax.
In this syntax, subsection names follow the same restrictions as for section
names.
All the other lines are recognized as setting variables, in the form
All the other lines (and the remainder of the line after the section
header) are recognized as setting variables, in the form
'name = value'. If there is no equal sign on the line, the entire line
is taken as 'name' and the variable is recognized as boolean "true".
The variable names are case-insensitive and only alphanumeric
@@ -456,7 +457,9 @@ If the alias expansion is prefixed with an exclamation point,
it will be treated as a shell command. For example, defining
"alias.new = !gitk --all --not ORIG_HEAD", the invocation
"git new" is equivalent to running the shell command
"gitk --all --not ORIG_HEAD".
"gitk --all --not ORIG_HEAD". Note that shell commands will be
executed from the top-level directory of a repository, which may
not necessarily be the current directory.
apply.whitespace::
Tells 'git-apply' how to handle whitespaces, in the same way
@@ -1043,6 +1046,12 @@ http.sslKey::
over HTTPS. Can be overridden by the 'GIT_SSL_KEY' environment
variable.
http.sslCertPasswordProtected::
Enable git's password prompt for the SSL certificate. Otherwise
OpenSSL will prompt the user, possibly many times, if the
certificate or private key is encrypted. Can be overridden by the
'GIT_SSL_CERT_PASSWORD_PROTECTED' environment variable.
http.sslCAInfo::
File containing the certificates to verify the peer with when
fetching or pushing over HTTPS. Can be overridden by the
@@ -1319,6 +1328,9 @@ remote.<name>.url::
The URL of a remote repository. See linkgit:git-fetch[1] or
linkgit:git-push[1].
remote.<name>.pushurl::
The push URL of a remote repository. See linkgit:git-push[1].
remote.<name>.proxy::
For remotes that require curl (http, https and ftp), the URL to
the proxy to use for that remote. Set to the empty string to
@@ -1376,6 +1388,50 @@ rerere.enabled::
default enabled if you create `rr-cache` directory under
`$GIT_DIR`, but can be disabled by setting this option to false.
sendemail.identity::
A configuration identity. When given, causes values in the
'sendemail.<identity>' subsection to take precedence over
values in the 'sendemail' section. The default identity is
the value of 'sendemail.identity'.
sendemail.smtpencryption::
See linkgit:git-send-email[1] for description. Note that this
setting is not subject to the 'identity' mechanism.
sendemail.smtpssl::
Deprecated alias for 'sendemail.smtpencryption = ssl'.
sendemail.<identity>.*::
Identity-specific versions of the 'sendemail.*' parameters
found below, taking precedence over those when the this
identity is selected, through command-line or
'sendemail.identity'.
sendemail.aliasesfile::
sendemail.aliasfiletype::
sendemail.bcc::
sendemail.cc::
sendemail.cccmd::
sendemail.chainreplyto::
sendemail.confirm::
sendemail.envelopesender::
sendemail.from::
sendemail.multiedit::
sendemail.signedoffbycc::
sendemail.smtppass::
sendemail.suppresscc::
sendemail.suppressfrom::
sendemail.to::
sendemail.smtpserver::
sendemail.smtpserverport::
sendemail.smtpuser::
sendemail.thread::
sendemail.validate::
See linkgit:git-send-email[1] for description.
sendemail.signedoffcc::
Deprecated alias for 'sendemail.signedoffbycc'.
showbranch.default::
The default set of branches for linkgit:git-show-branch[1].
See linkgit:git-show-branch[1].

View File

@@ -1,4 +1,7 @@
The output format from "git-diff-index", "git-diff-tree",
Raw output format
-----------------
The raw output format from "git-diff-index", "git-diff-tree",
"git-diff-files" and "git diff --raw" are very similar.
These commands all compare two sets of things; what is
@@ -16,6 +19,9 @@ git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]::
git-diff-files [<pattern>...]::
compares the index and the files on the filesystem.
The "git-diff-tree" command begins its ouput by printing the hash of
what is being compared. After that, all the commands print one output
line per changed file.
An output line is formatted this way:

View File

@@ -13,7 +13,7 @@ SYNOPSIS
[--3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--reject]
[--reject] [-q | --quiet]
[<mbox> | <Maildir>...]
'git am' (--skip | --resolved | --abort)
@@ -39,6 +39,10 @@ OPTIONS
--keep::
Pass `-k` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).
-q::
--quiet::
Be quiet. Only print error messages.
-u::
--utf8::
Pass `-u` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).

View File

@@ -164,9 +164,8 @@ to do it for you by issuing the command:
$ git bisect skip # Current version cannot be tested
------------
But computing the commit to test may be slower afterwards and git may
eventually not be able to tell the first bad commit among a bad commit
and one or more skipped commits.
But git may eventually be unable to tell the first bad commit among
a bad commit and one or more skipped commits.
You can even skip a range of commits, instead of just one commit,
using the "'<commit1>'..'<commit2>'" notation. For example:

View File

@@ -43,8 +43,7 @@ omit diff output for unmerged entries and just show "Unmerged".
-q::
Remain silent even on nonexistent files
Output format
-------------
include::diff-format.txt[]

View File

@@ -34,8 +34,6 @@ include::diff-options.txt[]
'git-diff-index' say that all non-checked-out files are up
to date.
Output format
-------------
include::diff-format.txt[]
Operating Modes

View File

@@ -159,8 +159,7 @@ HEAD commits it finds, which is even more interesting.
in case you care).
Output format
-------------
include::diff-format.txt[]

View File

@@ -84,8 +84,7 @@ include::diff-options.txt[]
the diff to the named paths (you can give directory
names and get diff for all files under them).
Output format
-------------
include::diff-format.txt[]
EXAMPLES

View File

@@ -36,6 +36,17 @@ when encountering a signed tag. With 'strip', the tags will be made
unsigned, with 'verbatim', they will be silently exported
and with 'warn', they will be exported, but you will see a warning.
--tag-of-filtered-object=(abort|drop|rewrite)::
Specify how to handle tags whose tagged objectis filtered out.
Since revisions and files to export can be limited by path,
tagged objects may be filtered completely.
+
When asking to 'abort' (which is the default), this program will die
when encountering such a tag. With 'drop' it will omit such tags from
the output. With 'rewrite', if the tagged object is a commit, it will
rewrite the tag to tag an ancestor commit (via parent rewriting; see
linkgit:git-rev-list[1])
-M::
-C::
Perform move and/or copy detection, as described in the
@@ -71,6 +82,12 @@ marks the same across runs.
allow that. So fake a tagger to be able to fast-import the
output.
[git-rev-list-args...]::
A list of arguments, acceptable to 'git-rev-parse' and
'git-rev-list', that specifies the specific objects and references
to export. For example, `master\~10..master` causes the
current master reference to be exported along with all objects
added since its 10th ancestor commit.
EXAMPLES
--------

View File

@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout]
[--thread[=<style>]]
[--no-thread | --thread[=<style>]]
[(--attach|--inline)[=<boundary>] | --no-attach]
[-s | --signoff]
[-n | --numbered | -N | --no-numbered]
@@ -124,17 +124,25 @@ include::diff-options.txt[]
second part, with "Content-Disposition: inline".
--thread[=<style>]::
Add In-Reply-To and References headers to make the second and
subsequent mails appear as replies to the first. Also generates
the Message-Id header to reference.
--no-thread::
Controls addition of In-Reply-To and References headers to
make the second and subsequent mails appear as replies to the
first. Also controls generation of the Message-Id header to
reference.
+
The optional <style> argument can be either `shallow` or `deep`.
'shallow' threading makes every mail a reply to the head of the
series, where the head is chosen from the cover letter, the
`\--in-reply-to`, and the first patch mail, in this order. 'deep'
threading makes every mail a reply to the previous one. If not
specified, defaults to the 'format.thread' configuration, or `shallow`
if that is not set.
threading makes every mail a reply to the previous one.
+
The default is --no-thread, unless the 'format.thread' configuration
is set. If --thread is specified without a style, it defaults to the
style specified by 'format.thread' if any, or else `shallow`.
+
Beware that the default for 'git send-email' is to thread emails
itself. If you want 'git format-patch' to take care of hreading, you
will want to ensure that threading is disabled for 'git send-email'.
--in-reply-to=Message-Id::
Make the first mail (or all the mails with --no-thread) appear as a

View File

@@ -122,6 +122,14 @@ OPTIONS
-<num>::
A shortcut for specifying -C<num>.
-p::
--show-function::
Show the preceding line that contains the function name of
the match, unless the matching line is a function name itself.
The name is determined in the same way as 'git diff' works out
patch hunk headers (see 'Defining a custom hunk-header' in
linkgit:gitattributes[5]).
-f <file>::
Read patterns from <file>, one per line.

View File

@@ -11,7 +11,8 @@ SYNOPSIS
[verse]
'git pack-objects' [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty]
[--local] [--incremental] [--window=N] [--depth=N] [--all-progress]
[--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
[--revs [--unpacked | --all]*] [--stdout | base-name]
[--keep-true-parents] < object-list
DESCRIPTION
@@ -197,6 +198,10 @@ base-name::
to force the version for the generated pack index, and to force
64-bit index entries on objects located above the given offset.
--keep-true-parents::
With this option, parents that are hidden by grafts are packed
nevertheless.
Author
------

View File

@@ -17,26 +17,6 @@ routines to parse files under $GIT_DIR/remotes/ and
$GIT_DIR/branches/ and configuration variables that are related
to fetching, pulling and pushing.
The primary entry points are:
get_remote_refs_for_fetch::
Given the list of user-supplied `<repo> <refspec>...`,
return the list of refs to fetch after canonicalizing
them into `$GIT_DIR` relative paths
(e.g. `refs/heads/foo`). When `<refspec>...` is empty
the returned list of refs consists of the defaults
for the given `<repo>`, if specified in
`$GIT_DIR/remotes/`, `$GIT_DIR/branches/`, or `remote.*.fetch`
configuration.
get_remote_refs_for_push::
Given the list of user-supplied `<repo> <refspec>...`,
return the list of refs to push in a form suitable to be
fed to the 'git-send-pack' command. When `<refspec>...`
is empty the returned list of refs consists of the
defaults for the given `<repo>`, if specified in
`$GIT_DIR/remotes/`.
Author
------
Written by Junio C Hamano.

View File

@@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).
--dry-run::
Do everything except actually send the updates.
--porcelain::
Produce machine-readable output. The output status line for each ref
will be tab-separated and sent to stdout instead of stderr. The full
symbolic names of the refs will be given.
--tags::
All refs under `$GIT_DIR/refs/tags` are pushed, in
addition to refspecs explicitly listed on the command
@@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:
<flag> <summary> <from> -> <to> (<reason>)
-------------------------------
If --porcelain is used, then each line of the output is of the form:
-------------------------------
<flag> \t <from>:<to> \t <summary> (<reason>)
-------------------------------
flag::
A single character indicating the status of the ref. This is
blank for a successfully pushed ref, `!` for a ref that was

View File

@@ -236,6 +236,10 @@ OPTIONS
is used instead ('git-merge-recursive' when merging a single
head, 'git-merge-octopus' otherwise). This implies --merge.
-q::
--quiet::
Be quiet. Implies --no-stat.
-v::
--verbose::
Be verbose. Implies --stat.

View File

@@ -23,7 +23,7 @@ on the initial manual merge, and applying previously recorded
hand resolutions to their corresponding automerge results.
[NOTE]
You need to set the configuration variable rerere.enabled to
You need to set the configuration variable rerere.enabled in order to
enable this command.

View File

@@ -14,6 +14,7 @@ SYNOPSIS
[ \--max-age=timestamp ]
[ \--min-age=timestamp ]
[ \--sparse ]
[ \--merges ]
[ \--no-merges ]
[ \--first-parent ]
[ \--remove-empty ]

View File

@@ -30,6 +30,11 @@ OPTIONS
Only meaningful in `--parseopt` mode. Tells the option parser to echo
out the first `--` met instead of skipping it.
--stop-at-non-option::
Only meaningful in `--parseopt` mode. Lets the option parser stop at
the first non-option argument. This can be used to parse sub-commands
that take options themself.
--sq-quote::
Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE
section below). In contrast to the `--sq` option below, this

View File

@@ -193,12 +193,12 @@ Automating
- 'self' will avoid including the sender
- 'cc' will avoid including anyone mentioned in Cc lines in the patch header
except for self (use 'self' for that).
- 'ccbody' will avoid including anyone mentioned in Cc lines in the
- 'bodycc' will avoid including anyone mentioned in Cc lines in the
patch body (commit message) except for self (use 'self' for that).
- 'sob' will avoid including anyone mentioned in Signed-off-by lines except
for self (use 'self' for that).
- 'cccmd' will avoid running the --cc-cmd.
- 'body' is equivalent to 'sob' + 'ccbody'
- 'body' is equivalent to 'sob' + 'bodycc'
- 'all' will suppress all auto cc values.
--
+
@@ -212,11 +212,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified.
value; if that is unspecified, default to --no-suppress-from.
--[no-]thread::
If this is set, the In-Reply-To header will be set on each email sent.
If disabled with "--no-thread", no emails will have the In-Reply-To
header set, unless specified with --in-reply-to.
Default is the value of the 'sendemail.thread' configuration
value; if that is unspecified, default to --thread.
If this is set, the In-Reply-To and References headers will be
added to each email sent. Whether each mail refers to the
previous email (`deep` threading per 'git format-patch'
wording) or to the first email (`shallow` threading) is
governed by "--[no-]chain-reply-to".
+
If disabled with "--no-thread", those headers will not be added
(unless specified with --in-reply-to). Default is the value of the
'sendemail.thread' configuration value; if that is unspecified,
default to --thread.
+
It is up to the user to ensure that no In-Reply-To header already
exists when 'git send-email' is asked to add it (especially note that
'git format-patch' can be configured to do the threading itself).
Failure to do so may not produce the expected result in the
recipient's MUA.
Administering

View File

@@ -9,8 +9,9 @@ SYNOPSIS
--------
[verse]
'git show-ref' [-q|--quiet] [--verify] [-h|--head] [-d|--dereference]
[-s|--hash] [--abbrev] [--tags] [--heads] [--] <pattern>...
'git show-ref' --exclude-existing[=pattern]
[-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags]
[--heads] [--] <pattern>...
'git show-ref' --exclude-existing[=<pattern>] < ref-list
DESCRIPTION
-----------
@@ -24,7 +25,7 @@ The --exclude-existing form is a filter that does the inverse, it shows the
refs from stdin that don't exist in the local repository.
Use of this utility is encouraged in favor of directly accessing files under
in the `.git` directory.
the `.git` directory.
OPTIONS
-------
@@ -48,9 +49,9 @@ OPTIONS
appended.
-s::
--hash::
--hash[=<n>]::
Only show the SHA1 hash, not the reference name. When also using
Only show the SHA1 hash, not the reference name. When combined with
--dereference the dereferenced tag will still be shown after the SHA1.
--verify::
@@ -59,11 +60,10 @@ OPTIONS
Aside from returning an error code of 1, it will also print an error
message if '--quiet' was not specified.
--abbrev::
--abbrev=len::
--abbrev[=<n>]::
Abbreviate the object name. When using `--hash`, you do
not have to say `--hash --abbrev`; `--hash=len` would do.
not have to say `--hash --abbrev`; `--hash=n` would do.
-q::
--quiet::
@@ -71,8 +71,7 @@ OPTIONS
Do not print any results to stdout. When combined with '--verify' this
can be used to silently check if a reference exists.
--exclude-existing::
--exclude-existing=pattern::
--exclude-existing[=<pattern>]::
Make 'git-show-ref' act as a filter that reads refs from stdin of the
form "^(?:<anything>\s)?<refname>(?:\^\{\})?$" and performs the

View File

@@ -9,10 +9,11 @@ SYNOPSIS
--------
[verse]
'git stash' list [<options>]
'git stash' ( show | drop ) [<stash>]
'git stash' ( pop | apply ) [--index] [<stash>]
'git stash' show [<stash>]
'git stash' drop [-q|--quiet] [<stash>]
'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
'git stash' [save [--keep-index] [<message>]]
'git stash' [save [--keep-index] [-q|--quiet] [<message>]]
'git stash' clear
'git stash' create
@@ -41,7 +42,7 @@ is also possible).
OPTIONS
-------
save [--keep-index] [<message>]::
save [--keep-index] [-q|--quiet] [<message>]::
Save your local modifications to a new 'stash', and run `git reset
--hard` to revert them. This is the default action when no
@@ -75,7 +76,7 @@ show [<stash>]::
it will accept any format known to 'git-diff' (e.g., `git stash show
-p stash@\{1}` to view the second most recent stash in patch form).
pop [<stash>]::
pop [--index] [-q|--quiet] [<stash>]::
Remove a single stashed state from the stash list and apply it
on top of the current working tree state, i.e., do the inverse
@@ -93,7 +94,7 @@ longer apply the changes as they were originally).
+
When no `<stash>` is given, `stash@\{0}` is assumed.
apply [--index] [<stash>]::
apply [--index] [-q|--quiet] [<stash>]::
Like `pop`, but do not remove the state from the stash list.
@@ -115,7 +116,7 @@ clear::
Remove all the stashed states. Note that those states will then
be subject to pruning, and may be difficult or impossible to recover.
drop [<stash>]::
drop [-q|--quiet] [<stash>]::
Remove a single stashed state from the stash list. When no `<stash>`
is given, it removes the latest one. i.e. `stash@\{0}`

View File

@@ -115,8 +115,9 @@ init::
update::
Update the registered submodules, i.e. clone missing submodules and
checkout the commit specified in the index of the containing repository.
This will make the submodules HEAD be detached unless '--rebase' is
specified or the key `submodule.$name.update` is set to `rebase`.
This will make the submodules HEAD be detached unless '--rebase' or
'--merge' is specified or the key `submodule.$name.update` is set to
`rebase` or `merge`.
+
If the submodule is not yet initialized, and you just want to use the
setting as stored in .gitmodules, you can automatically initialize the
@@ -140,8 +141,9 @@ foreach::
the processing to terminate. This can be overridden by adding '|| :'
to the end of the command.
+
As an example, "git submodule foreach 'echo $path `git rev-parse HEAD`' will
show the path and currently checked out commit for each submodule.
As an example, +git submodule foreach \'echo $path {backtick}git
rev-parse HEAD{backtick}'+ will show the path and currently checked out
commit for each submodule.
sync::
Synchronizes submodules' remote URL configuration setting
@@ -180,6 +182,16 @@ OPTIONS
This option is only valid for the update command.
Don't fetch new objects from the remote site.
--merge::
This option is only valid for the update command.
Merge the commit recorded in the superproject into the current branch
of the submodule. If this option is given, the submodule's HEAD will
not be detached. If a merge failure prevents this process, you will
have to resolve the resulting conflicts within the submodule with the
usual conflict resolution tools.
If the key `submodule.$name.update` is set to `merge`, this option is
implicit.
--rebase::
This option is only valid for the update command.
Rebase the current branch onto the commit recorded in the

View File

@@ -3,7 +3,7 @@ git-svn(1)
NAME
----
git-svn - Bidirectional operation between a single Subversion branch and git
git-svn - Bidirectional operation between a Subversion repository and git
SYNOPSIS
--------
@@ -11,27 +11,25 @@ SYNOPSIS
DESCRIPTION
-----------
'git-svn' is a simple conduit for changesets between Subversion and git.
'git svn' is a simple conduit for changesets between Subversion and git.
It provides a bidirectional flow of changes between a Subversion and a git
repository.
'git-svn' can track a single Subversion branch simply by using a
URL to the branch, follow branches laid out in the Subversion recommended
method (trunk, branches, tags directories) with the --stdlayout option, or
follow branches in any layout with the -T/-t/-b options (see options to
'init' below, and also the 'clone' command).
'git svn' can track a standard Subversion repository,
following the common "trunk/branches/tags" layout, with the --stdlayout option.
It can also follow branches and tags in any layout with the -T/-t/-b options
(see options to 'init' below, and also the 'clone' command).
Once tracking a Subversion branch (with any of the above methods), the git
Once tracking a Subversion repository (with any of the above methods), the git
repository can be updated from Subversion by the 'fetch' command and
Subversion updated from git by the 'dcommit' command.
COMMANDS
--------
--
'init'::
Initializes an empty git repository with additional
metadata directories for 'git-svn'. The Subversion URL
metadata directories for 'git svn'. The Subversion URL
may be specified as a command-line argument, or as full
URL arguments to -T/-t/-b. Optionally, the target
directory to operate on can be specified as a second
@@ -48,8 +46,11 @@ COMMANDS
--stdlayout;;
These are optional command-line options for init. Each of
these flags can point to a relative repository path
(--tags=project/tags') or a full url
(--tags=https://foo.org/project/tags). The option --stdlayout is
(--tags=project/tags) or a full url
(--tags=https://foo.org/project/tags).
You can specify more than one --tags and/or --branches options, in case
your Subversion repository places tags or branches under multiple paths.
The option --stdlayout is
a shorthand way of setting trunk,tags,branches as the relative paths,
which is the Subversion default. If any of the other options are given
as well, they take precedence.
@@ -61,16 +62,6 @@ COMMANDS
Set the 'useSvnsyncProps' option in the [svn-remote] config.
--rewrite-root=<URL>;;
Set the 'rewriteRoot' option in the [svn-remote] config.
--use-log-author;;
When retrieving svn commits into git (as part of fetch, rebase, or
dcommit operations), look for the first From: or Signed-off-by: line
in the log message and use that as the author string.
--add-author-from;;
When committing to svn from git (as part of commit or dcommit
operations), if the existing log message doesn't already have a
From: or Signed-off-by: line, append a From: line based on the
git commit's author string. If you use this, then --use-log-author
will retrieve a valid author string for all commits.
--username=<USER>;;
For transports that SVN handles authentication for (http,
https, and plain svn), specify the username. For other
@@ -89,6 +80,17 @@ COMMANDS
When passed to 'init' or 'clone' this regular expression will
be preserved as a config key. See 'fetch' for a description
of '--ignore-paths'.
--no-minimize-url;;
When tracking multiple directories (using --stdlayout,
--branches, or --tags options), git svn will attempt to connect
to the root (or highest allowed level) of the Subversion
repository. This default allows better tracking of history if
entire projects are moved within a repository, but may cause
issues on repositories where read access restrictions are in
place. Passing '--no-minimize-url' will allow git svn to
accept URLs as-is without attempting to connect to a higher
level directory. This option is off by default when only
one URL/branch is tracked (it would do little good).
'fetch'::
Fetch unfetched revisions from the Subversion remote we are
@@ -98,12 +100,12 @@ COMMANDS
--localtime;;
Store Git commit times in the local timezone instead of UTC. This
makes 'git-log' (even without --date=local) show the same times
makes 'git log' (even without --date=local) show the same times
that `svn log` would in the local timezone.
--parent;;
Fetch only from the SVN parent of the current HEAD.
+
This doesn't interfere with interoperating with the Subversion
repository you cloned from, but if you wish for your local Git
repository to be able to interoperate with someone else's local Git
@@ -116,20 +118,39 @@ the same local timezone.
The '--ignore-paths' option should match for every 'fetch'
(including automatic fetches due to 'clone', 'dcommit',
'rebase', etc) on a given repository.
+
[verse]
config key: svn-remote.<name>.ignore-paths
If the ignore-paths config key is set and the command
line option is also given, both regular expressions
will be used.
+
If the ignore-paths config key is set and the command line option is
also given, both regular expressions will be used.
+
Examples:
+
--
Skip "doc*" directory for every fetch;;
+
------------------------------------------------------------------------
--ignore-paths="^doc"
------------------------------------------------------------------------
--ignore-paths="^doc" - skip "doc*" directory for every
fetch.
Skip "branches" and "tags" of first level directories;;
+
------------------------------------------------------------------------
--ignore-paths="^[^/]+/(?:branches|tags)"
------------------------------------------------------------------------
--
--ignore-paths="^[^/]+/(?:branches|tags)" - skip
"branches" and "tags" of first level directories.
--use-log-author;;
When retrieving svn commits into git (as part of fetch, rebase, or
dcommit operations), look for the first From: or Signed-off-by: line
in the log message and use that as the author string.
--add-author-from;;
When committing to svn from git (as part of commit or dcommit
operations), if the existing log message doesn't already have a
From: or Signed-off-by: line, append a From: line based on the
git commit's author string. If you use this, then --use-log-author
will retrieve a valid author string for all commits.
'clone'::
Runs 'init' and 'fetch'. It will automatically create a
@@ -137,29 +158,29 @@ Examples:
or if a second argument is passed; it will create a directory
and work within that. It accepts all arguments that the
'init' and 'fetch' commands accept; with the exception of
'--fetch-all'. After a repository is cloned, the 'fetch'
command will be able to update revisions without affecting
the working tree; and the 'rebase' command will be able
to update the working tree with the latest changes.
'--fetch-all' and '--parent'. After a repository is cloned,
the 'fetch' command will be able to update revisions without
affecting the working tree; and the 'rebase' command will be
able to update the working tree with the latest changes.
'rebase'::
This fetches revisions from the SVN parent of the current HEAD
and rebases the current (uncommitted to SVN) work against it.
This works similarly to `svn update` or 'git-pull' except that
it preserves linear history with 'git-rebase' instead of
'git-merge' for ease of dcommitting with 'git-svn'.
This accepts all options that 'git-svn fetch' and 'git-rebase'
+
This works similarly to `svn update` or 'git pull' except that
it preserves linear history with 'git rebase' instead of
'git merge' for ease of dcommitting with 'git svn'.
+
This accepts all options that 'git svn fetch' and 'git rebase'
accept. However, '--fetch-all' only fetches from the current
[svn-remote], and not all [svn-remote] definitions.
Like 'git-rebase'; this requires that the working tree be clean
+
Like 'git rebase'; this requires that the working tree be clean
and have no uncommitted changes.
-l;;
--local;;
Do not fetch remotely; only run 'git-rebase' against the
Do not fetch remotely; only run 'git rebase' against the
last fetched commit from the upstream SVN.
'dcommit'::
@@ -167,11 +188,12 @@ and have no uncommitted changes.
repository, and then rebase or reset (depending on whether or
not there is a diff between SVN and head). This will create
a revision in SVN for each commit in git.
It is recommended that you run 'git-svn' fetch and rebase (not
It is recommended that you run 'git svn' fetch and rebase (not
pull or merge) your commits against the latest changes in the
SVN repository.
An optional command-line argument may be specified as an
alternative to HEAD.
An optional revision or branch argument may be specified, and
causes 'git svn' to do all work on that revision/branch
instead of HEAD.
This is advantageous over 'set-tree' (below) because it produces
cleaner, more linear history.
+
@@ -179,18 +201,17 @@ and have no uncommitted changes.
After committing, do not rebase or reset.
--commit-url <URL>;;
Commit to this SVN URL (the full path). This is intended to
allow existing git-svn repositories created with one transport
allow existing 'git svn' repositories created with one transport
method (e.g. `svn://` or `http://` for anonymous read) to be
reused if a user is later given access to an alternate transport
method (e.g. `svn+ssh://` or `https://`) for commit.
+
[verse]
config key: svn-remote.<name>.commiturl
config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
Using this option for any other purpose (don't ask)
is very strongly discouraged.
--
+
Using this option for any other purpose (don't ask) is very strongly
discouraged.
'branch'::
Create a branch in the SVN repository.
@@ -204,6 +225,20 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
Create a tag by using the tags_subdir instead of the branches_subdir
specified during git svn init.
-d;;
--destination;;
If more than one --branches (or --tags) option was given to the 'init'
or 'clone' command, you must provide the location of the branch (or
tag) you wish to create in the SVN repository. The value of this
option must match one of the paths specified by a --branches (or
--tags) option. You can see these paths with the commands
+
git config --get-all svn-remote.<name>.branches
git config --get-all svn-remote.<name>.tags
+
where <name> is the name of the SVN repository as specified by the -R option to
'init' (or "svn" by default).
'tag'::
Create a tag in the SVN repository. This is a shorthand for
'branch -t'.
@@ -215,10 +250,12 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
The following features from `svn log' are supported:
+
--
-r <n>[:<n>];;
--revision=<n>[:<n>];;
is supported, non-numeric args are not:
HEAD, NEXT, BASE, PREV, etc ...
-v/--verbose;;
-v;;
--verbose;;
it's not completely compatible with the --verbose
output in svn log, but reasonably close.
--limit=<n>;;
@@ -241,7 +278,7 @@ NOTE: SVN itself only stores times in UTC and nothing else. The regular svn
client converts the UTC time to the local time (or based on the TZ=
environment). This command has the same behaviour.
+
Any other arguments are passed directly to 'git-log'
Any other arguments are passed directly to 'git log'
'blame'::
Show what revision and author last modified each line of a file. The
@@ -249,15 +286,14 @@ Any other arguments are passed directly to 'git-log'
`svn blame' by default. Like the SVN blame command,
local uncommitted changes in the working copy are ignored;
the version of the file in the HEAD revision is annotated. Unknown
arguments are passed directly to 'git-blame'.
arguments are passed directly to 'git blame'.
+
--git-format;;
Produce output in the same format as 'git-blame', but with
Produce output in the same format as 'git blame', but with
SVN revision numbers instead of git commit hashes. In this mode,
changes that haven't been committed to SVN (including local
working-copy edits) are shown as revision 0.
--
'find-rev'::
When given an SVN revision number of the form 'rN', returns the
corresponding git commit hash (this can optionally be followed by a
@@ -271,7 +307,7 @@ Any other arguments are passed directly to 'git-log'
absolutely no attempts to do patching when committing to SVN, it
simply overwrites files with those specified in the tree or
commit. All merging is assumed to have taken place
independently of 'git-svn' functions.
independently of 'git svn' functions.
'create-ignore'::
Recursively finds the svn:ignore property on directories and
@@ -286,12 +322,12 @@ Any other arguments are passed directly to 'git-log'
'commit-diff'::
Commits the diff of two tree-ish arguments from the
command-line. This command does not rely on being inside an `git-svn
command-line. This command does not rely on being inside an `git svn
init`-ed repository. This command takes three arguments, (a) the
original tree to diff against, (b) the new tree result, (c) the
URL of the target Subversion repository. The final argument
(URL) may be omitted if you are working from a 'git-svn'-aware
repository (that has been `init`-ed with 'git-svn').
(URL) may be omitted if you are working from a 'git svn'-aware
repository (that has been `init`-ed with 'git svn').
The -r<revision> option is required for this.
'info'::
@@ -313,116 +349,170 @@ Any other arguments are passed directly to 'git-log'
Shows the Subversion externals. Use -r/--revision to specify a
specific revision.
--
'gc'::
Compress $GIT_DIR/svn/<refname>/unhandled.log files in .git/svn
and remove $GIT_DIR/svn/<refname>index files in .git/svn.
'reset'::
Undoes the effects of 'fetch' back to the specified revision.
This allows you to re-'fetch' an SVN revision. Normally the
contents of an SVN revision should never change and 'reset'
should not be necessary. However, if SVN permissions change,
or if you alter your --ignore-paths option, a 'fetch' may fail
with "not found in commit" (file not previously visible) or
"checksum mismatch" (missed a modification). If the problem
file cannot be ignored forever (with --ignore-paths) the only
way to repair the repo is to use 'reset'.
+
Only the rev_map and refs/remotes/git-svn are changed. Follow 'reset'
with a 'fetch' and then 'git reset' or 'git rebase' to move local
branches onto the new tree.
-r <n>;;
--revision=<n>;;
Specify the most recent revision to keep. All later revisions
are discarded.
-p;;
--parent;;
Discard the specified revision as well, keeping the nearest
parent instead.
Example:;;
Assume you have local changes in "master", but you need to refetch "r2".
+
------------
r1---r2---r3 remotes/git-svn
\
A---B master
------------
+
Fix the ignore-paths or SVN permissions problem that caused "r2" to
be incomplete in the first place. Then:
+
[verse]
git svn reset -r2 -p
git svn fetch
+
------------
r1---r2'--r3' remotes/git-svn
\
r2---r3---A---B master
------------
+
Then fixup "master" with 'git rebase'.
Do NOT use 'git merge' or your history will not be compatible with a
future 'dcommit'!
+
[verse]
git rebase --onto remotes/git-svn A^ master
+
------------
r1---r2'--r3' remotes/git-svn
\
A'--B' master
------------
OPTIONS
-------
--
--shared[={false|true|umask|group|all|world|everybody}]::
--template=<template_directory>::
Only used with the 'init' command.
These are passed directly to 'git-init'.
These are passed directly to 'git init'.
-r <ARG>::
--revision <ARG>::
Used with the 'fetch' command.
Used with the 'fetch' command.
+
This allows revision ranges for partial/cauterized history
to be supported. $NUMBER, $NUMBER1:$NUMBER2 (numeric ranges),
$NUMBER:HEAD, and BASE:$NUMBER are all supported.
+
This can allow you to make partial mirrors when running fetch;
but is generally not recommended because history will be skipped
and lost.
-::
--stdin::
Only used with the 'set-tree' command.
Only used with the 'set-tree' command.
+
Read a list of commits from stdin and commit them in reverse
order. Only the leading sha1 is read from each line, so
'git-rev-list --pretty=oneline' output can be used.
'git rev-list --pretty=oneline' output can be used.
--rmdir::
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
+
Remove directories from the SVN tree if there are no files left
behind. SVN can version empty directories, and they are not
removed by default if there are no files left in them. git
cannot version empty directories. Enabling this flag will make
the commit to SVN act like git.
+
[verse]
config key: svn.rmdir
-e::
--edit::
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
+
Edit the commit message before committing to SVN. This is off by
default for objects that are commits, and forced on when committing
tree objects.
+
[verse]
config key: svn.edit
-l<num>::
--find-copies-harder::
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
They are both passed directly to 'git-diff-tree'; see
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
+
They are both passed directly to 'git diff-tree'; see
linkgit:git-diff-tree[1] for more information.
+
[verse]
config key: svn.l
config key: svn.findcopiesharder
-A<filename>::
--authors-file=<filename>::
Syntax is compatible with the file used by 'git-cvsimport':
Syntax is compatible with the file used by 'git cvsimport':
+
------------------------------------------------------------------------
loginname = Joe User <user@example.com>
------------------------------------------------------------------------
If this option is specified and 'git-svn' encounters an SVN
committer name that does not exist in the authors-file, 'git-svn'
+
If this option is specified and 'git svn' encounters an SVN
committer name that does not exist in the authors-file, 'git svn'
will abort operation. The user will then have to add the
appropriate entry. Re-running the previous 'git-svn' command
appropriate entry. Re-running the previous 'git svn' command
after the authors-file is modified should continue operation.
+
[verse]
config key: svn.authorsfile
--authors-prog=<filename>::
If this option is specified, for each SVN committer name that does not
exist in the authors file, the given file is executed with the committer
name as the first argument. The program is expected to return a single
line of the form "Name <email>", which will be treated as if included in
the authors file.
If this option is specified, for each SVN committer name that
does not exist in the authors file, the given file is executed
with the committer name as the first argument. The program is
expected to return a single line of the form "Name <email>",
which will be treated as if included in the authors file.
-q::
--quiet::
Make 'git-svn' less verbose. Specify a second time to make it
Make 'git svn' less verbose. Specify a second time to make it
even less verbose.
--repack[=<n>]::
--repack-flags=<flags>::
These should help keep disk usage sane for large fetches
with many revisions.
These should help keep disk usage sane for large fetches with
many revisions.
+
--repack takes an optional argument for the number of revisions
to fetch before repacking. This defaults to repacking every
1000 commits fetched if no argument is specified.
--repack-flags are passed directly to 'git-repack'.
+
--repack-flags are passed directly to 'git repack'.
+
[verse]
config key: svn.repack
config key: svn.repackflags
@@ -431,41 +521,36 @@ config key: svn.repackflags
--merge::
-s<strategy>::
--strategy=<strategy>::
These are only used with the 'dcommit' and 'rebase' commands.
Passed directly to 'git-rebase' when using 'dcommit' if a
'git-reset' cannot be used (see 'dcommit').
These are only used with the 'dcommit' and 'rebase' commands.
+
Passed directly to 'git rebase' when using 'dcommit' if a
'git reset' cannot be used (see 'dcommit').
-n::
--dry-run::
This can be used with the 'dcommit', 'rebase', 'branch' and 'tag'
commands.
This can be used with the 'dcommit', 'rebase', 'branch' and
'tag' commands.
+
For 'dcommit', print out the series of git arguments that would show
which diffs would be committed to SVN.
+
For 'rebase', display the local branch associated with the upstream svn
repository associated with the current branch and the URL of svn
repository that will be fetched from.
+
For 'branch' and 'tag', display the urls that will be used for copying when
creating the branch or tag.
--
ADVANCED OPTIONS
----------------
--
-i<GIT_SVN_ID>::
--id <GIT_SVN_ID>::
This sets GIT_SVN_ID (instead of using the environment). This
allows the user to override the default refname to fetch from
when tracking a single URL. The 'log' and 'dcommit' commands
no longer require this switch as an argument.
This sets GIT_SVN_ID (instead of using the environment). This
allows the user to override the default refname to fetch from
when tracking a single URL. The 'log' and 'dcommit' commands
no longer require this switch as an argument.
-R<remote name>::
--svn-remote <remote name>::
@@ -479,33 +564,30 @@ no longer require this switch as an argument.
started tracking a branch and never tracked the trunk it was
descended from. This feature is enabled by default, use
--no-follow-parent to disable it.
+
[verse]
config key: svn.followparent
--
CONFIG FILE-ONLY OPTIONS
------------------------
--
svn.noMetadata::
svn-remote.<name>.noMetadata::
This gets rid of the 'git-svn-id:' lines at the end of every commit.
If you lose your .git/svn/git-svn/.rev_db file, 'git-svn' will not
This gets rid of the 'git-svn-id:' lines at the end of every commit.
+
If you lose your .git/svn/git-svn/.rev_db file, 'git svn' will not
be able to rebuild it and you won't be able to fetch again,
either. This is fine for one-shot imports.
The 'git-svn log' command will not work on repositories using
+
The 'git svn log' command will not work on repositories using
this, either. Using this conflicts with the 'useSvmProps'
option for (hopefully) obvious reasons.
svn.useSvmProps::
svn-remote.<name>.useSvmProps::
This allows 'git-svn' to re-map repository URLs and UUIDs from
mirrors created using SVN::Mirror (or svk) for metadata.
This allows 'git svn' to re-map repository URLs and UUIDs from
mirrors created using SVN::Mirror (or svk) for metadata.
+
If an SVN revision has a property, "svm:headrev", it is likely
that the revision was created by SVN::Mirror (also used by SVK).
The property contains a repository UUID and a revision. We want
@@ -522,23 +604,22 @@ svn-remote.<name>.useSvnsyncprops::
svn-remote.<name>.rewriteRoot::
This allows users to create repositories from alternate
URLs. For example, an administrator could run 'git-svn' on the
URLs. For example, an administrator could run 'git svn' on the
server locally (accessing via file://) but wish to distribute
the repository with a public http:// or svn:// URL in the
metadata so users of it will see the public URL.
svn.brokenSymlinkWorkaround::
This disables potentially expensive checks to workaround broken symlinks
checked into SVN by broken clients. Set this option to "false" if you
track a SVN repository with many empty blobs that are not symlinks.
This option may be changed while "git-svn" is running and take effect on
the next revision fetched. If unset, git-svn assumes this option to be
"true".
--
This disables potentially expensive checks to workaround
broken symlinks checked into SVN by broken clients. Set this
option to "false" if you track a SVN repository with many
empty blobs that are not symlinks. This option may be changed
while 'git svn' is running and take effect on the next
revision fetched. If unset, 'git svn' assumes this option to
be "true".
Since the noMetadata, rewriteRoot, useSvnsyncProps and useSvmProps
options all affect the metadata generated and used by 'git-svn'; they
options all affect the metadata generated and used by 'git svn'; they
*must* be set in the configuration file before any history is imported
and these settings should never be changed once they are set.
@@ -556,7 +637,7 @@ Tracking and contributing to the trunk of a Subversion-managed project:
git svn clone http://svn.example.com/project/trunk
# Enter the newly cloned directory:
cd trunk
# You should be on master branch, double-check with git-branch
# You should be on master branch, double-check with 'git branch'
git branch
# Do some work and commit locally to git:
git commit ...
@@ -587,12 +668,12 @@ Tracking and contributing to an entire Subversion-managed project
# of dcommit/rebase/show-ignore should be the same as above.
------------------------------------------------------------------------
The initial 'git-svn clone' can be quite time-consuming
The initial 'git svn clone' can be quite time-consuming
(especially for large Subversion repositories). If multiple
people (or one person with multiple machines) want to use
'git-svn' to interact with the same Subversion repository, you can
do the initial 'git-svn clone' to a repository on a server and
have each person clone that repository with 'git-clone':
'git svn' to interact with the same Subversion repository, you can
do the initial 'git svn clone' to a repository on a server and
have each person clone that repository with 'git clone':
------------------------------------------------------------------------
# Do the initial import on a server
@@ -606,7 +687,7 @@ have each person clone that repository with 'git-clone':
git fetch
# Create a local branch from one of the branches just fetched
git checkout -b master FETCH_HEAD
# Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server)
# Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server)
git svn init http://svn.example.com/project
# Pull the latest changes from Subversion
git svn rebase
@@ -615,7 +696,7 @@ have each person clone that repository with 'git-clone':
REBASE VS. PULL/MERGE
---------------------
Originally, 'git-svn' recommended that the 'remotes/git-svn' branch be
Originally, 'git svn' recommended that the 'remotes/git-svn' branch be
pulled or merged from. This is because the author favored
`git svn set-tree B` to commit a single head rather than the
`git svn set-tree A..B` notation to commit multiple commits.
@@ -623,14 +704,14 @@ pulled or merged from. This is because the author favored
If you use `git svn set-tree A..B` to commit several diffs and you do
not have the latest remotes/git-svn merged into my-branch, you should
use `git svn rebase` to update your work branch instead of `git pull` or
`git merge`. `pull`/`merge' can cause non-linear history to be flattened
`git merge`. `pull`/`merge` can cause non-linear history to be flattened
when committing into SVN, which can lead to merge commits reversing
previous commits in SVN.
DESIGN PHILOSOPHY
-----------------
Merge tracking in Subversion is lacking and doing branched development
with Subversion can be cumbersome as a result. While 'git-svn' can track
with Subversion can be cumbersome as a result. While 'git svn' can track
copy history (including branches and tags) for repositories adopting a
standard layout, it cannot yet represent merge history that happened
inside git back upstream to SVN users. Therefore it is advised that
@@ -641,25 +722,25 @@ CAVEATS
-------
For the sake of simplicity and interoperating with a less-capable system
(SVN), it is recommended that all 'git-svn' users clone, fetch and dcommit
directly from the SVN server, and avoid all 'git-clone'/'pull'/'merge'/'push'
(SVN), it is recommended that all 'git svn' users clone, fetch and dcommit
directly from the SVN server, and avoid all 'git clone'/'pull'/'merge'/'push'
operations between git repositories and branches. The recommended
method of exchanging code between git branches and users is
'git-format-patch' and 'git-am', or just 'dcommit'ing to the SVN repository.
'git format-patch' and 'git am', or just 'dcommit'ing to the SVN repository.
Running 'git-merge' or 'git-pull' is NOT recommended on a branch you
Running 'git merge' or 'git pull' is NOT recommended on a branch you
plan to 'dcommit' from. Subversion does not represent merges in any
reasonable or useful fashion; so users using Subversion cannot see any
merges you've made. Furthermore, if you merge or pull from a git branch
that is a mirror of an SVN branch, 'dcommit' may commit to the wrong
branch.
'git-clone' does not clone branches under the refs/remotes/ hierarchy or
any 'git-svn' metadata, or config. So repositories created and managed with
using 'git-svn' should use 'rsync' for cloning, if cloning is to be done
'git clone' does not clone branches under the refs/remotes/ hierarchy or
any 'git svn' metadata, or config. So repositories created and managed with
using 'git svn' should use 'rsync' for cloning, if cloning is to be done
at all.
Since 'dcommit' uses rebase internally, any git branches you 'git-push' to
Since 'dcommit' uses rebase internally, any git branches you 'git push' to
before 'dcommit' on will require forcing an overwrite of the existing ref
on the remote repository. This is generally considered bad practice,
see the linkgit:git-push[1] documentation for details.
@@ -669,6 +750,16 @@ already dcommitted. It is considered bad practice to --amend commits
you've already pushed to a remote repository for other users, and
dcommit with SVN is analogous to that.
When using multiple --branches or --tags, 'git svn' does not automatically
handle name collisions (for example, if two branches from different paths have
the same name, or if a branch and a tag have the same name). In these cases,
use 'init' to set up your git repository then, before your first 'fetch', edit
the .git/config file so that the branches and tags are associated with
different name spaces. For example:
branches = stable/*:refs/remotes/svn/stable/*
branches = debug/*:refs/remotes/svn/debug/*
BUGS
----
@@ -685,7 +776,7 @@ for git to detect them.
CONFIGURATION
-------------
'git-svn' stores [svn-remote] configuration information in the
'git svn' stores [svn-remote] configuration information in the
repository .git/config file. It is similar the core git
[remote] sections except 'fetch' keys do not accept glob
arguments; but they are instead handled by the 'branches'
@@ -706,7 +797,7 @@ Keep in mind that the '\*' (asterisk) wildcard of the local ref
however the remote wildcard may be anywhere as long as it's an
independent path component (surrounded by '/' or EOL). This
type of configuration is not automatically created by 'init' and
should be manually entered with a text-editor or using 'git-config'.
should be manually entered with a text-editor or using 'git config'.
SEE ALSO
--------

View File

@@ -43,9 +43,16 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
* link:v1.6.3.2/git.html[documentation for release 1.6.3.2]
* link:v1.6.4/git.html[documentation for release 1.6.4]
* release notes for
link:RelNotes-1.6.4.txt[1.6.4].
* link:v1.6.3.4/git.html[documentation for release 1.6.3.4]
* release notes for
link:RelNotes-1.6.3.4.txt[1.6.3.4],
link:RelNotes-1.6.3.3.txt[1.6.3.3],
link:RelNotes-1.6.3.2.txt[1.6.3.2],
link:RelNotes-1.6.3.1.txt[1.6.3.1],
link:RelNotes-1.6.3.txt[1.6.3].

View File

@@ -35,9 +35,11 @@ submodule.<name>.update::
If 'checkout' (the default), the new commit specified in the
superproject will be checked out in the submodule on a detached HEAD.
If 'rebase', the current branch of the submodule will be rebased onto
the commit specified in the superproject.
the commit specified in the superproject. If 'merge', the commit
specified in the superproject will be merged into the current branch
in the submodule.
This config option is overridden if 'git submodule update' is given
the '--rebase' option.
the '--merge' or '--rebase' options.
EXAMPLES

View File

@@ -332,11 +332,11 @@ alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------
This operation is safe even if Alice has uncommitted local changes.
The range notation HEAD..FETCH_HEAD" means "show everything that is reachable
from the FETCH_HEAD but exclude anything that is reachable from HEAD.
The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable
from the FETCH_HEAD but exclude anything that is reachable from HEAD".
Alice already knows everything that leads to her current state (HEAD),
and reviewing what Bob has in his state (FETCH_HEAD) that she has not
seen with this command
and reviews what Bob has in his state (FETCH_HEAD) that she has not
seen with this command.
If Alice wants to visualize what Bob did since their histories forked
she can issue the following command:
@@ -375,9 +375,9 @@ it easier:
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------
With this, Alice can perform the first part of the "pull" operation alone using the
'git-fetch' command without merging them with her own branch,
using:
With this, Alice can perform the first part of the "pull" operation
alone using the 'git-fetch' command without merging them with her own
branch, using:
-------------------------------------
alice$ git fetch bob
@@ -566,22 +566,22 @@ $ git log v2.5.. Makefile # commits since v2.5 which modify
You can also give 'git-log' a "range" of commits where the first is not
necessarily an ancestor of the second; for example, if the tips of
the branches "stable-release" and "master" diverged from a common
the branches "stable" and "master" diverged from a common
commit some time ago, then
-------------------------------------
$ git log stable..experimental
$ git log stable..master
-------------------------------------
will list commits made in the experimental branch but not in the
will list commits made in the master branch but not in the
stable branch, while
-------------------------------------
$ git log experimental..stable
$ git log master..stable
-------------------------------------
will show the list of commits made on the stable branch but not
the experimental branch.
the master branch.
The 'git-log' command has a weakness: it must present commits in a
list. When the history has lines of development that diverged and

View File

@@ -201,6 +201,10 @@ endif::git-rev-list[]
Stop when a given path disappears from the tree.
--merges::
Print only merge commits.
--no-merges::
Do not print commits with more than one parent.

View File

@@ -18,6 +18,10 @@ struct remote
An array of all of the url_nr URLs configured for the remote
`pushurl`::
An array of all of the pushurl_nr push URLs configured for the remote
`push`::
An array of refspecs configured for pushing, with

View File

@@ -27,10 +27,13 @@ config file would appear like this:
------------
[remote "<name>"]
url = <url>
pushurl = <pushurl>
push = <refspec>
fetch = <refspec>
------------
The `<pushurl>` is used for pushes only. It is optional and defaults
to `<url>`.
Named file in `$GIT_DIR/remotes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

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

View File

@@ -61,6 +61,8 @@ all::
#
# Define NO_LIBGEN_H if you don't have libgen.h.
#
# Define NEEDS_LIBGEN if your libgen needs -lgen when linking
#
# Define NO_SYS_SELECT_H if you don't have sys/select.h.
#
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
@@ -194,6 +196,8 @@ all::
#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
#
# Define NO_REGEX if you have no or inferior regex support in your C library.
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -723,6 +727,8 @@ ifeq ($(uname_S),SunOS)
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
NO_REGEX = YesPlease
NO_EXTERNAL_GREP = YesPlease
ifeq ($(uname_R),5.7)
NEEDS_RESOLV = YesPlease
NO_IPV6 = YesPlease
@@ -750,7 +756,7 @@ ifeq ($(uname_S),SunOS)
endif
INSTALL = /usr/ucb/install
TAR = gtar
BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__
BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
endif
ifeq ($(uname_O),Cygwin)
NO_D_TYPE_IN_DIRENT = YesPlease
@@ -825,18 +831,31 @@ ifeq ($(uname_S),GNU)
NO_STRLCPY=YesPlease
NO_MKSTEMPS = YesPlease
endif
ifeq ($(uname_S),IRIX)
NO_SETENV = YesPlease
NO_UNSETENV = YesPlease
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
NO_MKSTEMPS = YesPlease
NO_MKDTEMP = YesPlease
NO_MMAP = YesPlease
NO_EXTERNAL_GREP = UnfortunatelyYes
SNPRINTF_RETURNS_BOGUS = YesPlease
SHELL_PATH = /usr/gnu/bin/bash
NEEDS_LIBGEN = YesPlease
endif
ifeq ($(uname_S),IRIX64)
NO_IPV6=YesPlease
NO_SETENV=YesPlease
NO_UNSETENV = YesPlease
NO_STRCASESTR=YesPlease
NO_MEMMEM = YesPlease
NO_MKSTEMPS = YesPlease
NO_STRLCPY = YesPlease
NO_SOCKADDR_STORAGE=YesPlease
NO_MKDTEMP = YesPlease
NO_MMAP = YesPlease
NO_EXTERNAL_GREP = UnfortunatelyYes
SNPRINTF_RETURNS_BOGUS = YesPlease
SHELL_PATH=/usr/gnu/bin/bash
BASIC_CFLAGS += -DPATH_MAX=1024
# for now, build 32-bit version
BASIC_LDFLAGS += -L/usr/lib32
NEEDS_LIBGEN = YesPlease
endif
ifeq ($(uname_S),HP-UX)
NO_IPV6=YesPlease
@@ -883,9 +902,10 @@ ifneq (,$(findstring MINGW,$(uname_S)))
USE_NED_ALLOCATOR = YesPlease
UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
NO_REGEX = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o
EXTLIBS += -lws2_32
X = .exe
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
@@ -1014,6 +1034,9 @@ ifdef NEEDS_LIBICONV
endif
EXTLIBS += $(ICONV_LINK) -liconv
endif
ifdef NEEDS_LIBGEN
EXTLIBS += -lgen
endif
ifdef NEEDS_SOCKET
EXTLIBS += -lsocket
endif
@@ -1199,6 +1222,10 @@ endif
ifdef UNRELIABLE_FSTAT
BASIC_CFLAGS += -DUNRELIABLE_FSTAT
endif
ifdef NO_REGEX
COMPAT_CFLAGS += -Icompat/regex
COMPAT_OBJS += compat/regex/regex.o
endif
ifdef USE_NED_ALLOCATOR
COMPAT_CFLAGS += -DUSE_NED_ALLOCATOR -DOVERRIDE_STRDUP -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR -Icompat/nedmalloc
@@ -1463,7 +1490,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
builtin-revert.o wt-status.o: wt-status.h
$(LIB_FILE): $(LIB_OBJS)
@@ -1632,15 +1659,16 @@ ifneq (,$X)
endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ $(RM) "$$execdir/git-add$X" && \
{ test "$$bindir/" = "$$execdir/" || \
{ $(RM) "$$execdir/git$X" && \
test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \
ln "$$bindir/git$X" "$$execdir/git$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git$X"; } ; } && \
{ for p in $(BUILT_INS); do \
$(RM) "$$execdir/$$p" && \
ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \
ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
done; } && \
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"

View File

@@ -41,13 +41,13 @@ const char *make_absolute_path(const char *path)
if (*buf) {
if (!*cwd && !getcwd(cwd, sizeof(cwd)))
die ("Could not get current working directory");
die_errno ("Could not get current working directory");
if (chdir(buf))
die ("Could not switch to '%s'", buf);
die_errno ("Could not switch to '%s'", buf);
}
if (!getcwd(buf, PATH_MAX))
die ("Could not get current working directory");
die_errno ("Could not get current working directory");
if (last_elem) {
int len = strlen(buf);
@@ -63,7 +63,7 @@ const char *make_absolute_path(const char *path)
if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
len = readlink(buf, next_buf, PATH_MAX);
if (len < 0)
die ("Invalid symlink: %s", buf);
die_errno ("Invalid symlink '%s'", buf);
if (PATH_MAX <= len)
die("symbolic link too long: %s", buf);
next_buf[len] = '\0';
@@ -75,7 +75,7 @@ const char *make_absolute_path(const char *path)
}
if (*cwd && chdir(cwd))
die ("Could not change back to '%s'", cwd);
die_errno ("Could not change back to '%s'", cwd);
return buf;
}
@@ -109,7 +109,7 @@ const char *make_nonrelative_path(const char *path)
} else {
const char *cwd = get_pwd_cwd();
if (!cwd)
die("Cannot determine the current working directory");
die_errno("Cannot determine the current working directory");
if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
die("Too long path: %.*s", 60, path);
}

5
attr.c
View File

@@ -35,8 +35,7 @@ static struct git_attr *(git_attr_hash[HASHSIZE]);
static unsigned hash_name(const char *name, int namelen)
{
unsigned val = 0;
unsigned char c;
unsigned val = 0, c;
while (namelen--) {
c = *name++;
@@ -556,6 +555,8 @@ static void prepare_attr_stack(const char *path, int dirlen)
}
}
strbuf_release(&pathbuf);
/*
* Finally push the "info" one at the top of the stack.
*/

View File

@@ -91,7 +91,7 @@ void encode_85(char *buf, const unsigned char *data, int bytes)
unsigned acc = 0;
int cnt;
for (cnt = 24; cnt >= 0; cnt -= 8) {
int ch = *data++;
unsigned ch = *data++;
acc |= ch << cnt;
if (--bytes == 0)
break;

View File

@@ -454,14 +454,14 @@ static int read_bisect_refs(void)
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
void read_bisect_paths(struct argv_array *array)
static void read_bisect_paths(struct argv_array *array)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_NAMES");
FILE *fp = fopen(filename, "r");
if (!fp)
die("Could not open file '%s': %s", filename, strerror(errno));
die_errno("Could not open file '%s'", filename);
while (strbuf_getline(&str, fp, '\n') != EOF) {
char *quoted;
@@ -585,16 +585,49 @@ struct commit_list *filter_skipped(struct commit_list *list,
return filtered;
}
static struct commit_list *apply_skip_ratio(struct commit_list *list,
int count,
int skip_num, int skip_denom)
#define PRN_MODULO 32768
/*
* This is a pseudo random number generator based on "man 3 rand".
* It is not used properly because the seed is the argument and it
* is increased by one between each call, but that should not matter
* for this application.
*/
int get_prn(int count) {
count = count * 1103515245 + 12345;
return ((unsigned)(count/65536) % PRN_MODULO);
}
/*
* Custom integer square root from
* http://en.wikipedia.org/wiki/Integer_square_root
*/
static int sqrti(int val)
{
float d, x = val;
if (val == 0)
return 0;
do {
float y = (x + (float)val / x) / 2;
d = (y > x) ? y - x : x - y;
x = y;
} while (d >= 0.5);
return (int)x;
}
static struct commit_list *skip_away(struct commit_list *list, int count)
{
int index, i;
struct commit_list *cur, *previous;
int prn, index, i;
prn = get_prn(count);
index = (count * prn / PRN_MODULO) * sqrti(prn) / sqrti(PRN_MODULO);
cur = list;
previous = NULL;
index = count * skip_num / skip_denom;
for (i = 0; cur; cur = cur->next, i++) {
if (i == index) {
@@ -614,7 +647,6 @@ static struct commit_list *managed_skipped(struct commit_list *list,
struct commit_list **tried)
{
int count, skipped_first;
int skip_num, skip_denom;
*tried = NULL;
@@ -626,11 +658,7 @@ static struct commit_list *managed_skipped(struct commit_list *list,
if (!skipped_first)
return list;
/* Use alternatively 1/5, 2/5 and 3/5 as skip ratio. */
skip_num = count % 3 + 1;
skip_denom = 5;
return apply_skip_ratio(list, count, skip_num, skip_denom);
return skip_away(list, count);
}
static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
@@ -712,8 +740,7 @@ static void mark_expected_rev(char *bisect_rev_hex)
int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
die("could not create file '%s': %s",
filename, strerror(errno));
die_errno("could not create file '%s'", filename);
bisect_rev_hex[len] = '\n';
write_or_die(fd, bisect_rev_hex, len + 1);
@@ -780,7 +807,7 @@ static void handle_bad_merge_base(void)
exit(1);
}
void handle_skipped_merge_base(const unsigned char *mb)
static void handle_skipped_merge_base(const unsigned char *mb)
{
char *mb_hex = sha1_to_hex(mb);
char *bad_hex = sha1_to_hex(current_bad_sha1);

View File

@@ -172,7 +172,7 @@ void create_branch(const char *head,
lock = lock_any_ref_for_update(ref.buf, NULL, 0);
if (!lock)
die("Failed to lock ref for update: %s.", strerror(errno));
die_errno("Failed to lock ref for update");
if (reflog)
log_all_ref_updates = 1;
@@ -188,7 +188,7 @@ void create_branch(const char *head,
setup_tracking(name, real_ref, track);
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
die_errno("Failed to write ref");
strbuf_release(&ref);
free(real_ref);

View File

@@ -97,35 +97,6 @@ static void treat_gitlinks(const char **pathspec)
}
}
static void fill_directory(struct dir_struct *dir, const char **pathspec,
int ignored_too)
{
const char *path, *base;
int baselen;
/* Set up the default git porcelain excludes */
memset(dir, 0, sizeof(*dir));
if (!ignored_too) {
dir->flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(dir);
}
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
/* Read the directory and prune it */
read_directory(dir, path, base, baselen, pathspec);
if (pathspec)
prune_directory(dir, pathspec, baselen);
}
static void refresh(int verbose, const char **pathspec)
{
char *seen;
@@ -189,7 +160,7 @@ int interactive_add(int argc, const char **argv, const char *prefix)
return status;
}
int edit_patch(int argc, const char **argv, const char *prefix)
static int edit_patch(int argc, const char **argv, const char *prefix)
{
char *file = xstrdup(git_path("ADD_EDIT.patch"));
const char *apply_argv[] = { "apply", "--recount", "--cached",
@@ -220,7 +191,7 @@ int edit_patch(int argc, const char **argv, const char *prefix)
launch_editor(file, NULL, NULL);
if (stat(file, &st))
die("Could not stat '%s'", file);
die_errno("Could not stat '%s'", file);
if (!st.st_size)
die("Empty patch. Aborted.");
@@ -298,6 +269,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int add_new_files;
int require_pathspec;
git_config(add_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_add_options,
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
@@ -305,8 +278,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (add_interactive)
exit(interactive_add(argc - 1, argv + 1, prefix));
git_config(add_config, NULL);
if (edit_interactive)
return(edit_patch(argc, argv, prefix));
argc--;
@@ -343,9 +314,21 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die("index file corrupt");
treat_gitlinks(pathspec);
if (add_new_files)
if (add_new_files) {
int baselen;
/* Set up the default git porcelain excludes */
memset(&dir, 0, sizeof(dir));
if (!ignored_too) {
dir.flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(&dir);
}
/* This picks up the paths that are not tracked */
fill_directory(&dir, pathspec, ignored_too);
baselen = fill_directory(&dir, pathspec);
if (pathspec)
prune_directory(&dir, pathspec, baselen);
}
if (refresh_only) {
refresh(verbose, pathspec);

View File

@@ -280,7 +280,7 @@ static void say_patch_name(FILE *output, const char *pre,
static void read_patch_file(struct strbuf *sb, int fd)
{
if (strbuf_read(sb, fd, 0) < 0)
die("git apply: read returned %s", strerror(errno));
die_errno("git apply: failed to read");
/*
* Make sure that we have some slop in the buffer
@@ -2614,7 +2614,7 @@ static int get_current_sha1(const char *path, unsigned char *sha1)
static void build_fake_ancestor(struct patch *list, const char *filename)
{
struct patch *patch;
struct index_state result = { 0 };
struct index_state result = { NULL };
int fd;
/* Once we start supporting the reverse patch, it may be
@@ -2823,8 +2823,8 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
} else {
if (!cached) {
if (lstat(path, &st) < 0)
die("unable to stat newly created file %s",
path);
die_errno("unable to stat newly created file '%s'",
path);
fill_stat_cache_info(ce, &st);
}
if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
@@ -2864,7 +2864,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
strbuf_release(&nbuf);
if (close(fd) < 0)
die("closing file %s: %s", path, strerror(errno));
die_errno("closing file '%s'", path);
return 0;
}
@@ -2913,7 +2913,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
++nr;
}
}
die("unable to write file %s mode %o", path, mode);
die_errno("unable to write file '%s' mode %o", path, mode);
}
static void create_file(struct patch *patch)
@@ -3356,7 +3356,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
fd = open(arg, O_RDONLY);
if (fd < 0)
die("can't open patch '%s': %s", arg, strerror(errno));
die_errno("can't open patch '%s'", arg);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
errs |= apply_patch(fd, arg, options);

View File

@@ -13,10 +13,10 @@ static void create_output_file(const char *output_file)
{
int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (output_fd < 0)
die("could not create archive file: %s ", output_file);
die_errno("could not create archive file '%s'", output_file);
if (output_fd != 1) {
if (dup2(output_fd, 1) < 0)
die("could not redirect output");
die_errno("could not redirect output");
else
close(output_fd);
}

View File

@@ -2008,23 +2008,23 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
if (contents_from) {
if (stat(contents_from, &st) < 0)
die("Cannot stat %s", contents_from);
die_errno("Cannot stat '%s'", contents_from);
read_from = contents_from;
}
else {
if (lstat(path, &st) < 0)
die("Cannot lstat %s", path);
die_errno("Cannot lstat '%s'", path);
read_from = path;
}
mode = canon_mode(st.st_mode);
switch (st.st_mode & S_IFMT) {
case S_IFREG:
if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
die("cannot open or read %s", read_from);
die_errno("cannot open or read '%s'", read_from);
break;
case S_IFLNK:
if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
die("cannot readlink %s", read_from);
die_errno("cannot readlink '%s'", read_from);
break;
default:
die("unsupported file type %s", read_from);
@@ -2035,7 +2035,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
contents_from = "standard input";
mode = 0;
if (strbuf_read(&buf, 0, 0) < 0)
die("read error %s from stdin", strerror(errno));
die_errno("failed to read from stdin");
}
convert_to_git(path, buf.buf, buf.len, &buf, 0);
origin->file.ptr = buf.buf;
@@ -2261,8 +2261,7 @@ parse_done:
argc = parse_options_end(&ctx);
if (revs_file && read_ancestry(revs_file))
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
die_errno("reading graft file '%s' failed", revs_file);
if (cmd_is_annotate) {
output_option |= OUTPUT_ANNOTATE_COMPAT;
@@ -2350,7 +2349,7 @@ parse_done:
setup_work_tree();
if (!has_string_in_work_tree(path))
die("cannot stat path %s: %s", path, strerror(errno));
die_errno("cannot stat path '%s'", path);
}
setup_revisions(argc, argv, &revs, NULL);

View File

@@ -191,7 +191,7 @@ struct ref_item {
struct ref_list {
struct rev_info revs;
int index, alloc, maxwidth;
int index, alloc, maxwidth, verbose, abbrev;
struct ref_item *list;
struct commit_list *with_commit;
int kinds;
@@ -240,21 +240,24 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
if (ARRAY_SIZE(ref_kind) <= i)
return 0;
commit = lookup_commit_reference_gently(sha1, 1);
if (!commit)
return error("branch '%s' does not point at a commit", refname);
/* Filter with with_commit if specified */
if (!is_descendant_of(commit, ref_list->with_commit))
return 0;
/* Don't add types the caller doesn't want */
if ((kind & ref_list->kinds) == 0)
return 0;
if (merge_filter != NO_FILTER)
add_pending_object(&ref_list->revs,
(struct object *)commit, refname);
commit = NULL;
if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
commit = lookup_commit_reference_gently(sha1, 1);
if (!commit)
return error("branch '%s' does not point at a commit", refname);
/* Filter with with_commit if specified */
if (!is_descendant_of(commit, ref_list->with_commit))
return 0;
if (merge_filter != NO_FILTER)
add_pending_object(&ref_list->revs,
(struct object *)commit, refname);
}
/* Resize buffer */
if (ref_list->index >= ref_list->alloc) {
@@ -415,18 +418,38 @@ static int calc_maxwidth(struct ref_list *refs)
return w;
}
static void show_detached(struct ref_list *ref_list)
{
struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
struct ref_item item;
item.name = xstrdup("(no branch)");
item.len = strlen(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
item.commit = head_commit;
if (item.len > ref_list->maxwidth)
ref_list->maxwidth = item.len;
print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
free(item.name);
}
}
static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)
{
int i;
struct ref_list ref_list;
struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);
memset(&ref_list, 0, sizeof(ref_list));
ref_list.kinds = kinds;
ref_list.verbose = verbose;
ref_list.abbrev = abbrev;
ref_list.with_commit = with_commit;
if (merge_filter != NO_FILTER)
init_revisions(&ref_list.revs, NULL);
for_each_ref(append_ref, &ref_list);
for_each_rawref(append_ref, &ref_list);
if (merge_filter != NO_FILTER) {
struct commit *filter;
filter = lookup_commit_reference_gently(merge_filter_ref, 0);
@@ -442,19 +465,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
detached = (detached && (kinds & REF_LOCAL_BRANCH));
if (detached && head_commit &&
is_descendant_of(head_commit, with_commit)) {
struct ref_item item;
item.name = xstrdup("(no branch)");
item.len = strlen(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
item.commit = head_commit;
if (item.len > ref_list.maxwidth)
ref_list.maxwidth = item.len;
print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, "");
free(item.name);
}
if (detached)
show_detached(&ref_list);
for (i = 0; i < ref_list.index; i++) {
int current = !detached &&

View File

@@ -33,7 +33,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
const char *path, *base;
static const char **pathspec;
struct strbuf buf = STRBUF_INIT;
const char *qname;
@@ -78,16 +77,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
pathspec = get_pathspec(prefix, argv);
read_cache();
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
read_directory(&dir, path, base, baselen, pathspec);
fill_directory(&dir, pathspec);
if (pathspec)
seen = xmalloc(argc > 0 ? argc : 1);

View File

@@ -141,7 +141,7 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
if (is_bare) {
struct strbuf result = STRBUF_INIT;
strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
dir = strbuf_detach(&result, 0);
dir = strbuf_detach(&result, NULL);
} else
dir = xstrndup(start, end - start);
/*
@@ -220,13 +220,13 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
dir = opendir(src->buf);
if (!dir)
die("failed to open %s", src->buf);
die_errno("failed to open '%s'", src->buf);
if (mkdir(dest->buf, 0777)) {
if (errno != EEXIST)
die("failed to create directory %s", dest->buf);
die_errno("failed to create directory '%s'", dest->buf);
else if (stat(dest->buf, &buf))
die("failed to stat %s", dest->buf);
die_errno("failed to stat '%s'", dest->buf);
else if (!S_ISDIR(buf.st_mode))
die("%s exists and is not a directory", dest->buf);
}
@@ -252,17 +252,16 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
}
if (unlink(dest->buf) && errno != ENOENT)
die("failed to unlink %s: %s",
dest->buf, strerror(errno));
die_errno("failed to unlink '%s'", dest->buf);
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;
if (option_local)
die("failed to create link %s", dest->buf);
die_errno("failed to create link '%s'", dest->buf);
option_no_hardlinks = 1;
}
if (copy_file(dest->buf, src->buf, 0666))
die("failed to copy file to %s", dest->buf);
die_errno("failed to copy file to '%s'", dest->buf);
}
closedir(dir);
}
@@ -420,11 +419,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (!option_bare) {
junk_work_tree = work_tree;
if (safe_create_leading_directories_const(work_tree) < 0)
die("could not create leading directories of '%s': %s",
work_tree, strerror(errno));
die_errno("could not create leading directories of '%s'",
work_tree);
if (!dest_exists && mkdir(work_tree, 0755))
die("could not create work tree dir '%s': %s.",
work_tree, strerror(errno));
die_errno("could not create work tree dir '%s'.",
work_tree);
set_git_work_tree(work_tree);
}
junk_git_dir = git_dir;

View File

@@ -124,7 +124,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
}
if (strbuf_read(&buffer, 0, 0) < 0)
die("git commit-tree: read returned %s", strerror(errno));
die_errno("git commit-tree: failed to read");
if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
printf("%s\n", sha1_to_hex(commit_sha1));

View File

@@ -434,12 +434,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
if (isatty(0))
fprintf(stderr, "(reading log message from standard input)\n");
if (strbuf_read(&sb, 0, 0) < 0)
die("could not read log from standard input");
die_errno("could not read log from standard input");
hook_arg1 = "message";
} else if (logfile) {
if (strbuf_read_file(&sb, logfile, 0) < 0)
die("could not read log file '%s': %s",
logfile, strerror(errno));
die_errno("could not read log file '%s'",
logfile);
hook_arg1 = "message";
} else if (use_message) {
buffer = strstr(use_message_buffer, "\n\n");
@@ -450,16 +450,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
hook_arg2 = use_message;
} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
die("could not read MERGE_MSG: %s", strerror(errno));
die_errno("could not read MERGE_MSG");
hook_arg1 = "merge";
} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
die("could not read SQUASH_MSG: %s", strerror(errno));
die_errno("could not read SQUASH_MSG");
hook_arg1 = "squash";
} else if (template_file && !stat(template_file, &statbuf)) {
if (strbuf_read_file(&sb, template_file, 0) < 0)
die("could not read %s: %s",
template_file, strerror(errno));
die_errno("could not read '%s'", template_file);
hook_arg1 = "template";
}
@@ -472,8 +471,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
fp = fopen(git_path(commit_editmsg), "w");
if (fp == NULL)
die("could not open %s: %s",
git_path(commit_editmsg), strerror(errno));
die_errno("could not open '%s'", git_path(commit_editmsg));
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, 0);
@@ -497,7 +495,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
}
if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
die("could not write commit template: %s", strerror(errno));
die_errno("could not write commit template");
strbuf_release(&sb);
@@ -940,8 +938,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
fp = fopen(git_path("MERGE_HEAD"), "r");
if (fp == NULL)
die("could not open %s for reading: %s",
git_path("MERGE_HEAD"), strerror(errno));
die_errno("could not open '%s' for reading",
git_path("MERGE_HEAD"));
while (strbuf_getline(&m, fp, '\n') != EOF) {
unsigned char sha1[20];
if (get_sha1_hex(m.buf, sha1) < 0)
@@ -952,8 +950,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_release(&m);
if (!stat(git_path("MERGE_MODE"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0)
die("could not read MERGE_MODE: %s",
strerror(errno));
die_errno("could not read MERGE_MODE");
if (!strcmp(sb.buf, "no-ff"))
allow_fast_forward = 0;
}
@@ -967,8 +964,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
/* Finally, get the commit message */
strbuf_reset(&sb);
if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
int saved_errno = errno;
rollback_index_files();
die("could not read commit message");
die("could not read commit message: %s", strerror(saved_errno));
}
/* Truncate the message just before the diff, if any. */

View File

@@ -383,8 +383,8 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
check_argc(argc, 0, 0);
if (git_config(show_all_config, NULL) < 0) {
if (config_exclusive_filename)
die("unable to read config file %s: %s",
config_exclusive_filename, strerror(errno));
die_errno("unable to read config file '%s'",
config_exclusive_filename);
else
die("error processing config file(s)");
}

View File

@@ -70,7 +70,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
usage(builtin_diff_usage);
if (lstat(path, &st))
die("'%s': %s", path, strerror(errno));
die_errno("failed to stat '%s'", path);
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
die("'%s': not a regular file or symlink", path);

View File

@@ -23,7 +23,8 @@ static const char *fast_export_usage[] = {
};
static int progress;
static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT;
static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
static int fake_missing_tagger;
static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -42,6 +43,20 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
return 0;
}
static int parse_opt_tag_of_filtered_mode(const struct option *opt,
const char *arg, int unset)
{
if (unset || !strcmp(arg, "abort"))
tag_of_filtered_mode = ABORT;
else if (!strcmp(arg, "drop"))
tag_of_filtered_mode = DROP;
else if (!strcmp(arg, "rewrite"))
tag_of_filtered_mode = REWRITE;
else
return error("Unknown tag-of-filtered mode: %s", arg);
return 0;
}
static struct decoration idnums;
static uint32_t last_idnum;
@@ -119,7 +134,7 @@ static void handle_object(const unsigned char *sha1)
printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
if (size && fwrite(buf, size, 1, stdout) != 1)
die ("Could not write blob %s", sha1_to_hex(sha1));
die_errno ("Could not write blob '%s'", sha1_to_hex(sha1));
printf("\n");
show_progress();
@@ -289,6 +304,23 @@ static void handle_tag(const char *name, struct tag *tag)
char *buf;
const char *tagger, *tagger_end, *message;
size_t message_size = 0;
struct object *tagged;
int tagged_mark;
struct commit *p;
/* Trees have no identifer in fast-export output, thus we have no way
* to output tags of trees, tags of tags of trees, etc. Simply omit
* such tags.
*/
tagged = tag->tagged;
while (tagged->type == OBJ_TAG) {
tagged = ((struct tag *)tagged)->tagged;
}
if (tagged->type == OBJ_TREE) {
warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.",
sha1_to_hex(tag->object.sha1));
return;
}
buf = read_sha1_file(tag->object.sha1, &type, &size);
if (!buf)
@@ -333,10 +365,45 @@ static void handle_tag(const char *name, struct tag *tag)
}
}
/* handle tag->tagged having been filtered out due to paths specified */
tagged = tag->tagged;
tagged_mark = get_object_mark(tagged);
if (!tagged_mark) {
switch(tag_of_filtered_mode) {
case ABORT:
die ("Tag %s tags unexported object; use "
"--tag-of-filtered-object=<mode> to handle it.",
sha1_to_hex(tag->object.sha1));
case DROP:
/* Ignore this tag altogether */
return;
case REWRITE:
if (tagged->type != OBJ_COMMIT) {
die ("Tag %s tags unexported %s!",
sha1_to_hex(tag->object.sha1),
typename(tagged->type));
}
p = (struct commit *)tagged;
for (;;) {
if (p->parents && p->parents->next)
break;
if (p->object.flags & UNINTERESTING)
break;
if (!(p->object.flags & TREESAME))
break;
if (!p->parents)
die ("Can't find replacement commit for tag %s\n",
sha1_to_hex(tag->object.sha1));
p = p->parents->item;
}
tagged_mark = get_object_mark(&p->object);
}
}
if (!prefixcmp(name, "refs/tags/"))
name += 10;
printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
name, get_object_mark(tag->tagged),
name, tagged_mark,
(int)(tagger_end - tagger), tagger,
tagger == tagger_end ? "" : "\n",
(int)message_size, (int)message_size, message ? message : "");
@@ -428,21 +495,27 @@ static void export_marks(char *file)
uint32_t mark;
struct object_decoration *deco = idnums.hash;
FILE *f;
int e = 0;
f = fopen(file, "w");
if (!f)
error("Unable to open marks file %s for writing", file);
error("Unable to open marks file %s for writing.", file);
for (i = 0; i < idnums.size; i++) {
if (deco->base && deco->base->type == 1) {
mark = ptr_to_mark(deco->decoration);
fprintf(f, ":%"PRIu32" %s\n", mark,
sha1_to_hex(deco->base->sha1));
if (fprintf(f, ":%"PRIu32" %s\n", mark,
sha1_to_hex(deco->base->sha1)) < 0) {
e = 1;
break;
}
}
deco++;
}
if (ferror(f) || fclose(f))
e |= ferror(f);
e |= fclose(f);
if (e)
error("Unable to write marks file %s.", file);
}
@@ -451,7 +524,7 @@ static void import_marks(char *input_file)
char line[512];
FILE *f = fopen(input_file, "r");
if (!f)
die("cannot read %s: %s", input_file, strerror(errno));
die_errno("cannot read '%s'", input_file);
while (fgets(line, sizeof(line), f)) {
uint32_t mark;
@@ -498,6 +571,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
"select handling of signed tags",
parse_opt_signed_tag_mode),
OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
"select handling of tags that tag filtered objects",
parse_opt_tag_of_filtered_mode),
OPT_STRING(0, "export-marks", &export_filename, "FILE",
"Dump marks to this file"),
OPT_STRING(0, "import-marks", &import_filename, "FILE",
@@ -514,6 +590,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
revs.topo_order = 1;
revs.show_source = 1;
revs.rewrite_parents = 1;
argc = setup_revisions(argc, argv, &revs, NULL);
argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0);
if (argc > 1)
@@ -524,18 +603,13 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
get_tags_and_duplicates(&revs.pending, &extra_refs);
revs.topo_order = 1;
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
revs.diffopt.format_callback = show_filemodify;
DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
while ((commit = get_revision(&revs))) {
if (has_unshown_parent(commit)) {
struct commit_list *parent = commit->parents;
add_object_array(&commit->object, NULL, &commits);
for (; parent; parent = parent->next)
if (!parent->item->util)
parent->item->util = commit->util;
}
else {
handle_commit(commit, &revs);

View File

@@ -8,7 +8,7 @@ static char *get_stdin(void)
{
struct strbuf buf = STRBUF_INIT;
if (strbuf_read(&buf, 0, 1024) < 0) {
die("error reading standard input: %s", strerror(errno));
die_errno("error reading standard input");
}
return strbuf_detach(&buf, NULL);
}

View File

@@ -400,14 +400,14 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
/*
* We would want to bypass the object transfer altogether if
* everything we are going to fetch already exists and connected
* everything we are going to fetch already exists and is connected
* locally.
*
* The refs we are going to fetch are in to_fetch (nr_heads in
* total). If running
* The refs we are going to fetch are in ref_map. If running
*
* $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
* $ git rev-list --objects --stdin --not --all
*
* (feeding all the refs in ref_map on its standard input)
* does not error out, that means everything reachable from the
* refs we are going to fetch exists and is connected to some of
* our existing refs.
@@ -416,8 +416,9 @@ static int quickfetch(struct ref *ref_map)
{
struct child_process revlist;
struct ref *ref;
char **argv;
int i, err;
int err;
const char *argv[] = {"rev-list",
"--quiet", "--objects", "--stdin", "--not", "--all", NULL};
/*
* If we are deepening a shallow clone we already have these
@@ -429,34 +430,46 @@ static int quickfetch(struct ref *ref_map)
if (depth)
return -1;
for (i = 0, ref = ref_map; ref; ref = ref->next)
i++;
if (!i)
if (!ref_map)
return 0;
argv = xmalloc(sizeof(*argv) * (i + 6));
i = 0;
argv[i++] = xstrdup("rev-list");
argv[i++] = xstrdup("--quiet");
argv[i++] = xstrdup("--objects");
for (ref = ref_map; ref; ref = ref->next)
argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1));
argv[i++] = xstrdup("--not");
argv[i++] = xstrdup("--all");
argv[i++] = NULL;
memset(&revlist, 0, sizeof(revlist));
revlist.argv = (const char**)argv;
revlist.argv = argv;
revlist.git_cmd = 1;
revlist.no_stdin = 1;
revlist.no_stdout = 1;
revlist.no_stderr = 1;
err = run_command(&revlist);
revlist.in = -1;
for (i = 0; argv[i]; i++)
free(argv[i]);
free(argv);
return err;
err = start_command(&revlist);
if (err) {
error("could not run rev-list");
return err;
}
/*
* If rev-list --stdin encounters an unknown commit, it terminates,
* which will cause SIGPIPE in the write loop below.
*/
sigchain_push(SIGPIPE, SIG_IGN);
for (ref = ref_map; ref; ref = ref->next) {
if (write_in_full(revlist.in, sha1_to_hex(ref->old_sha1), 40) < 0 ||
write_in_full(revlist.in, "\n", 1) < 0) {
if (errno != EPIPE && errno != EINVAL)
error("failed write to rev-list: %s", strerror(errno));
err = -1;
break;
}
}
if (close(revlist.in)) {
error("failed to close rev-list's stdin: %s", strerror(errno));
err = -1;
}
sigchain_pop(SIGPIPE);
return finish_command(&revlist) || err;
}
static int fetch_refs(struct transport *transport, struct ref *ref_map)

View File

@@ -368,12 +368,11 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
if (inpath && strcmp(inpath, "-")) {
in = fopen(inpath, "r");
if (!in)
die("cannot open %s", inpath);
die_errno("cannot open '%s'", inpath);
}
if (strbuf_read(&input, fileno(in), 0) < 0)
die("could not read input file %s", strerror(errno));
die_errno("could not read input file");
ret = fmt_merge_msg(merge_summary, &input, &output);
if (ret)
return ret;

View File

@@ -104,7 +104,7 @@ static int mark_object(struct object *obj, int type, void *data)
static void mark_object_reachable(struct object *obj)
{
mark_object(obj, OBJ_ANY, 0);
mark_object(obj, OBJ_ANY, NULL);
}
static int traverse_one_object(struct object *obj, struct object *parent)
@@ -217,7 +217,7 @@ static void check_unreachable_object(struct object *obj)
return;
}
if (!(f = fopen(filename, "w")))
die("Could not open %s", filename);
die_errno("Could not open '%s'", filename);
if (obj->type == OBJ_BLOB) {
enum object_type type;
unsigned long size;
@@ -225,15 +225,15 @@ static void check_unreachable_object(struct object *obj)
&type, &size);
if (buf) {
if (fwrite(buf, size, 1, f) != 1)
die("Could not write %s: %s",
filename, strerror(errno));
die_errno("Could not write '%s'",
filename);
free(buf);
}
} else
fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
if (fclose(f))
die("Could not finish %s: %s",
filename, strerror(errno));
die_errno("Could not finish '%s'",
filename);
}
return;
}
@@ -292,7 +292,7 @@ static int fsck_sha1(const unsigned char *sha1)
fprintf(stderr, "Checking %s %s\n",
typename(obj->type), sha1_to_hex(obj->sha1));
if (fsck_walk(obj, mark_used, 0))
if (fsck_walk(obj, mark_used, NULL))
objerror(obj, "broken links");
if (fsck_object(obj, check_strict, fsck_error_func))
return -1;

View File

@@ -11,6 +11,7 @@
#include "tree-walk.h"
#include "builtin.h"
#include "parse-options.h"
#include "userdiff.h"
#include "grep.h"
#ifndef NO_EXTERNAL_GREP
@@ -30,6 +31,12 @@ static int grep_config(const char *var, const char *value, void *cb)
{
struct grep_opt *opt = cb;
switch (userdiff_config(var, value)) {
case 0: break;
case -1: return -1;
default: return 0;
}
if (!strcmp(var, "color.grep")) {
opt->color = git_config_colorbool(var, value, -1);
return 0;
@@ -278,6 +285,17 @@ static int flush_grep(struct grep_opt *opt,
argc -= 2;
}
if (opt->pre_context || opt->post_context) {
/*
* grep handles hunk marks between files, but we need to
* do that ourselves between multiple calls.
*/
if (opt->show_hunk_mark)
write_or_die(1, "--\n", 3);
else
opt->show_hunk_mark = 1;
}
status = exec_grep(argc, argv);
if (kept_0) {
@@ -594,7 +612,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
patterns = fopen(arg, "r");
if (!patterns)
die("'%s': %s", arg, strerror(errno));
die_errno("cannot open '%s'", arg);
while (strbuf_getline(&sb, patterns, '\n') == 0) {
/* ignore empty line like grep does */
if (sb.len == 0)
@@ -710,6 +728,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
"show <n> context lines after matches"),
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
context_callback),
OPT_BOOLEAN('p', "show-function", &opt.funcname,
"show a line with the function name before matches"),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, "file",
"read patterns from file", file_callback),
@@ -778,7 +798,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
argc--;
}
if (opt.color && !opt.color_external)
if ((opt.color && !opt.color_external) || opt.funcname)
external_grep_allowed = 0;
if (!opt.pattern_list)
die("no pattern given.");

View File

@@ -394,7 +394,7 @@ static void get_html_page_path(struct strbuf *page_path, const char *page)
* HTML.
*/
#ifndef open_html
void open_html(const char *path)
static void open_html(const char *path)
{
execl_git_cmd("web--browse", "-c", "help.browser", path, NULL);
}

View File

@@ -61,20 +61,20 @@ static void copy_templates_1(char *path, int baselen,
memcpy(template + template_baselen, de->d_name, namelen+1);
if (lstat(path, &st_git)) {
if (errno != ENOENT)
die("cannot stat %s", path);
die_errno("cannot stat '%s'", path);
}
else
exists = 1;
if (lstat(template, &st_template))
die("cannot stat template %s", template);
die_errno("cannot stat template '%s'", template);
if (S_ISDIR(st_template.st_mode)) {
DIR *subdir = opendir(template);
int baselen_sub = baselen + namelen;
int template_baselen_sub = template_baselen + namelen;
if (!subdir)
die("cannot opendir %s", template);
die_errno("cannot opendir '%s'", template);
path[baselen_sub++] =
template[template_baselen_sub++] = '/';
path[baselen_sub] =
@@ -91,16 +91,17 @@ static void copy_templates_1(char *path, int baselen,
int len;
len = readlink(template, lnk, sizeof(lnk));
if (len < 0)
die("cannot readlink %s", template);
die_errno("cannot readlink '%s'", template);
if (sizeof(lnk) <= len)
die("insanely long symlink %s", template);
lnk[len] = 0;
if (symlink(lnk, path))
die("cannot symlink %s %s", lnk, path);
die_errno("cannot symlink '%s' '%s'", lnk, path);
}
else if (S_ISREG(st_template.st_mode)) {
if (copy_file(path, template, st_template.st_mode))
die("cannot copy %s to %s", template, path);
die_errno("cannot copy '%s' to '%s'", template,
path);
}
else
error("ignoring template %s", template);
@@ -350,7 +351,7 @@ static int guess_repository_type(const char *git_dir)
if (!strcmp(".", git_dir))
return 1;
if (!getcwd(cwd, sizeof(cwd)))
die("cannot tell cwd");
die_errno("cannot tell cwd");
if (!strcmp(git_dir, cwd))
return 1;
/*
@@ -440,11 +441,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (!git_work_tree_cfg) {
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
if (!getcwd(git_work_tree_cfg, PATH_MAX))
die ("Cannot access current working directory.");
die_errno ("Cannot access current working directory");
}
if (access(get_git_work_tree(), X_OK))
die ("Cannot access work tree '%s'",
get_git_work_tree());
die_errno ("Cannot access work tree '%s'",
get_git_work_tree());
}
set_git_dir(make_absolute_path(git_dir));

View File

@@ -94,7 +94,7 @@ static void show_early_header(struct rev_info *rev, const char *stage, int nr)
printf("Final output: %d %s\n", nr, stage);
}
struct itimerval early_output_timer;
static struct itimerval early_output_timer;
static void log_show_early(struct rev_info *revs, struct commit_list *list)
{
@@ -977,7 +977,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
strbuf_addch(&buf, '\n');
}
rev.extra_headers = strbuf_detach(&buf, 0);
rev.extra_headers = strbuf_detach(&buf, NULL);
if (start_number < 0)
start_number = 1;
@@ -1013,8 +1013,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (use_stdout)
die("standard output, or directory, which one?");
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
die("Could not create directory %s",
output_directory);
die_errno("Could not create directory '%s'",
output_directory);
}
if (rev.pending.nr == 1) {

View File

@@ -161,12 +161,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)
/* For cached/deleted files we don't need to even do the readdir */
if (show_others || show_killed) {
const char *path = ".", *base = "";
int baselen = prefix_len;
if (baselen)
path = base = prefix;
read_directory(dir, path, base, baselen, pathspec);
fill_directory(dir, pathspec);
if (show_others)
show_other_files(dir);
if (show_killed)

View File

@@ -81,7 +81,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0)
die("cannot open output file %s", name);
die_errno("cannot open output file '%s'", name);
output = fdopen(fd, "w");
/* Copy it out, while searching for a line that begins with
@@ -91,7 +91,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
int is_partial = len && buf[len-1] != '\n';
if (fwrite(buf, 1, len, output) != len)
die("cannot write output");
die_errno("cannot write output");
len = read_line_with_nul(buf, sizeof(buf), mbox);
if (len == 0) {
@@ -99,7 +99,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
status = 1;
break;
}
die("cannot read mbox");
die_errno("cannot read mbox");
}
if (!is_partial && !is_bare && is_from_line(buf, len))
break; /* done with one message */

View File

@@ -268,7 +268,7 @@ static void squash_message(void)
printf("Squash commit -- not updating HEAD\n");
fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die("Could not write to %s", git_path("SQUASH_MSG"));
die_errno("Could not write to '%s'", git_path("SQUASH_MSG"));
init_revisions(&rev, NULL);
rev.ignore_merges = 1;
@@ -294,9 +294,9 @@ static void squash_message(void)
NULL, NULL, rev.date_mode, 0);
}
if (write(fd, out.buf, out.len) < 0)
die("Writing SQUASH_MSG: %s", strerror(errno));
die_errno("Writing SQUASH_MSG");
if (close(fd))
die("Finishing SQUASH_MSG: %s", strerror(errno));
die_errno("Finishing SQUASH_MSG");
strbuf_release(&out);
}
@@ -370,7 +370,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, remote);
resolve_ref(buf.buf, branch_head, 0, 0);
resolve_ref(buf.buf, branch_head, 0, NULL);
if (!hashcmp(remote_head->sha1, branch_head)) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
@@ -409,7 +409,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_addstr(&truname, "refs/heads/");
strbuf_addstr(&truname, remote);
strbuf_setlen(&truname, truname.len - len);
if (resolve_ref(truname.buf, buf_sha, 0, 0)) {
if (resolve_ref(truname.buf, buf_sha, 0, NULL)) {
strbuf_addf(msg,
"%s\t\tbranch '%s'%s of .\n",
sha1_to_hex(remote_head->sha1),
@@ -428,8 +428,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
fp = fopen(git_path("FETCH_HEAD"), "r");
if (!fp)
die("could not open %s for reading: %s",
git_path("FETCH_HEAD"), strerror(errno));
die_errno("could not open '%s' for reading",
git_path("FETCH_HEAD"));
strbuf_getline(&line, fp, '\n');
fclose(fp);
ptr = strstr(line.buf, "\tnot-for-merge\t");
@@ -764,7 +764,8 @@ static int suggest_conflicts(void)
fp = fopen(git_path("MERGE_MSG"), "a");
if (!fp)
die("Could not open %s for writing", git_path("MERGE_MSG"));
die_errno("Could not open '%s' for writing",
git_path("MERGE_MSG"));
fprintf(fp, "\nConflicts:\n");
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
@@ -1189,27 +1190,29 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
sha1_to_hex(j->item->object.sha1));
fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die("Could open %s for writing",
git_path("MERGE_HEAD"));
die_errno("Could not open '%s' for writing",
git_path("MERGE_HEAD"));
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
die("Could not write to %s", git_path("MERGE_HEAD"));
die_errno("Could not write to '%s'", git_path("MERGE_HEAD"));
close(fd);
strbuf_addch(&merge_msg, '\n');
fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die("Could open %s for writing", git_path("MERGE_MSG"));
die_errno("Could not open '%s' for writing",
git_path("MERGE_MSG"));
if (write_in_full(fd, merge_msg.buf, merge_msg.len) !=
merge_msg.len)
die("Could not write to %s", git_path("MERGE_MSG"));
die_errno("Could not write to '%s'", git_path("MERGE_MSG"));
close(fd);
fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
die("Could open %s for writing", git_path("MERGE_MODE"));
die_errno("Could not open '%s' for writing",
git_path("MERGE_MODE"));
strbuf_reset(&buf);
if (!allow_fast_forward)
strbuf_addf(&buf, "no-ff");
if (write_in_full(fd, buf.buf, buf.len) != buf.len)
die("Could not write to %s", git_path("MERGE_MODE"));
die_errno("Could not write to '%s'", git_path("MERGE_MODE"));
close(fd);
}

View File

@@ -24,14 +24,10 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
result[count] = NULL;
for (i = 0; i < count; i++) {
int length = strlen(result[i]);
if (length > 0 && result[i][length - 1] == '/') {
if (length > 0 && is_dir_sep(result[i][length - 1]))
result[i] = xmemdupz(result[i], length - 1);
}
if (base_name) {
const char *last_slash = strrchr(result[i], '/');
if (last_slash)
result[i] = last_slash + 1;
}
if (base_name)
result[i] = basename((char *)result[i]);
}
return get_pathspec(prefix, result);
}
@@ -209,7 +205,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
printf("Renaming %s to %s\n", src, dst);
if (!show_only && mode != INDEX &&
rename(src, dst) < 0 && !ignore_errors)
die ("renaming %s failed: %s", src, strerror(errno));
die_errno ("renaming '%s' failed", src);
if (mode == WORKING_DIRECTORY)
continue;

View File

@@ -536,11 +536,9 @@ static void write_pack_file(void)
base_name, sha1_to_hex(sha1));
free_pack_by_name(tmpname);
if (adjust_perm(pack_tmp_name, mode))
die("unable to make temporary pack file readable: %s",
strerror(errno));
die_errno("unable to make temporary pack file readable");
if (rename(pack_tmp_name, tmpname))
die("unable to rename temporary pack file: %s",
strerror(errno));
die_errno("unable to rename temporary pack file");
/*
* Packs are runtime accessed in their mtime
@@ -566,11 +564,9 @@ static void write_pack_file(void)
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
base_name, sha1_to_hex(sha1));
if (adjust_perm(idx_tmp_name, mode))
die("unable to make temporary index file readable: %s",
strerror(errno));
die_errno("unable to make temporary index file readable");
if (rename(idx_tmp_name, tmpname))
die("unable to rename temporary index file: %s",
strerror(errno));
die_errno("unable to rename temporary index file");
free(idx_tmp_name);
free(pack_tmp_name);
@@ -653,8 +649,7 @@ static void rehash_objects(void)
static unsigned name_hash(const char *name)
{
unsigned char c;
unsigned hash = 0;
unsigned c, hash = 0;
if (!name)
return 0;
@@ -1880,7 +1875,7 @@ static void read_object_list_from_stdin(void)
if (!ferror(stdin))
die("fgets returned NULL, not EOF, not error!");
if (errno != EINTR)
die("fgets: %s", strerror(errno));
die_errno("fgets");
clearerr(stdin);
continue;
}
@@ -2260,6 +2255,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
die("bad %s", arg);
continue;
}
if (!strcmp(arg, "--keep-true-parents")) {
grafts_replace_parents = 0;
continue;
}
usage(pack_usage);
}

View File

@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const push_usage[] = {
"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
NULL,
};
@@ -64,36 +64,11 @@ static void setup_push_tracking(void)
add_refspec(refspec.buf);
}
static const char *warn_unconfigured_push_msg[] = {
"You did not specify any refspecs to push, and the current remote",
"has not configured any push refspecs. The default action in this",
"case is to push all matching refspecs, that is, all branches",
"that exist both locally and remotely will be updated. This may",
"not necessarily be what you want to happen.",
"",
"You can specify what action you want to take in this case, and",
"avoid seeing this message again, by configuring 'push.default' to:",
" 'nothing' : Do not push anything",
" 'matching' : Push all matching branches (default)",
" 'tracking' : Push the current branch to whatever it is tracking",
" 'current' : Push the current branch"
};
static void warn_unconfigured_push(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
warning("%s", warn_unconfigured_push_msg[i]);
}
static void setup_default_push_refspecs(void)
{
git_config(git_default_config, NULL);
switch (push_default) {
case PUSH_DEFAULT_UNSPECIFIED:
warn_unconfigured_push();
/* fallthrough */
default:
case PUSH_DEFAULT_MATCHING:
add_refspec(":");
break;
@@ -117,6 +92,8 @@ static int do_push(const char *repo, int flags)
{
int i, errs;
struct remote *remote = remote_get(repo);
const char **url;
int url_nr;
if (!remote) {
if (repo)
@@ -152,9 +129,16 @@ static int do_push(const char *repo, int flags)
setup_default_push_refspecs();
}
errs = 0;
for (i = 0; i < remote->url_nr; i++) {
if (remote->pushurl_nr) {
url = remote->pushurl;
url_nr = remote->pushurl_nr;
} else {
url = remote->url;
url_nr = remote->url_nr;
}
for (i = 0; i < url_nr; i++) {
struct transport *transport =
transport_get(remote, remote->url[i]);
transport_get(remote, url[i]);
int err;
if (receivepack)
transport_set_option(transport,
@@ -163,14 +147,14 @@ static int do_push(const char *repo, int flags)
transport_set_option(transport, TRANS_OPT_THIN, "yes");
if (flags & TRANSPORT_PUSH_VERBOSE)
fprintf(stderr, "Pushing to %s\n", remote->url[i]);
fprintf(stderr, "Pushing to %s\n", url[i]);
err = transport_push(transport, refspec_nr, refspec, flags);
err |= transport_disconnect(transport);
if (!err)
continue;
error("failed to push some refs to '%s'", remote->url[i]);
error("failed to push some refs to '%s'", url[i]);
errs++;
}
return !!errs;
@@ -191,6 +175,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),

View File

@@ -123,27 +123,27 @@ static struct command *commands;
static const char pre_receive_hook[] = "hooks/pre-receive";
static const char post_receive_hook[] = "hooks/post-receive";
static int hook_status(int code, const char *hook_name)
static int run_status(int code, const char *cmd_name)
{
switch (code) {
case 0:
return 0;
case -ERR_RUN_COMMAND_FORK:
return error("hook fork failed");
return error("fork of %s failed", cmd_name);
case -ERR_RUN_COMMAND_EXEC:
return error("hook execute failed");
return error("execute of %s failed", cmd_name);
case -ERR_RUN_COMMAND_PIPE:
return error("hook pipe failed");
return error("pipe failed");
case -ERR_RUN_COMMAND_WAITPID:
return error("waitpid failed");
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
return error("waitpid is confused");
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
return error("%s died of signal", hook_name);
return error("%s died of signal", cmd_name);
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
return error("%s died strangely", hook_name);
return error("%s died strangely", cmd_name);
default:
error("%s exited with error code %d", hook_name, -code);
error("%s exited with error code %d", cmd_name, -code);
return -code;
}
}
@@ -174,7 +174,7 @@ static int run_receive_hook(const char *hook_name)
code = start_command(&proc);
if (code)
return hook_status(code, hook_name);
return run_status(code, hook_name);
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string) {
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
@@ -186,7 +186,7 @@ static int run_receive_hook(const char *hook_name)
}
}
close(proc.in);
return hook_status(finish_command(&proc), hook_name);
return run_status(finish_command(&proc), hook_name);
}
static int run_update_hook(struct command *cmd)
@@ -203,7 +203,7 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL;
return hook_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
return run_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
RUN_COMMAND_STDOUT_TO_STDERR),
update_hook);
}
@@ -394,7 +394,7 @@ static char update_post_hook[] = "hooks/post-update";
static void run_update_post_hook(struct command *cmd)
{
struct command *cmd_p;
int argc;
int argc, status;
const char **argv;
for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
@@ -417,8 +417,9 @@ static void run_update_post_hook(struct command *cmd)
argc++;
}
argv[argc] = NULL;
run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
| RUN_COMMAND_STDOUT_TO_STDERR);
status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
| RUN_COMMAND_STDOUT_TO_STDERR);
run_status(status, update_post_hook);
}
static void execute_commands(const char *unpacker_error)
@@ -534,24 +535,10 @@ static const char *unpack(void)
unpacker[i++] = hdr_arg;
unpacker[i++] = NULL;
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
switch (code) {
case 0:
if (!code)
return NULL;
case -ERR_RUN_COMMAND_FORK:
return "unpack fork failed";
case -ERR_RUN_COMMAND_EXEC:
return "unpack execute failed";
case -ERR_RUN_COMMAND_WAITPID:
return "waitpid failed";
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
return "waitpid is confused";
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
return "unpacker died of signal";
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
return "unpacker died strangely";
default:
return "unpacker exited with error code";
}
run_status(code, unpacker[0]);
return "unpack-objects abnormal exit";
} else {
const char *keeper[7];
int s, status, i = 0;
@@ -574,8 +561,11 @@ static const char *unpack(void)
ip.argv = keeper;
ip.out = -1;
ip.git_cmd = 1;
if (start_command(&ip))
status = start_command(&ip);
if (status) {
run_status(status, keeper[0]);
return "index-pack fork failed";
}
pack_lockfile = index_pack_lockfile(ip.out);
close(ip.out);
status = finish_command(&ip);
@@ -583,6 +573,7 @@ static const char *unpack(void)
reprepare_packed_git();
return NULL;
}
run_status(status, keeper[0]);
return "index-pack abnormal exit";
}
}

View File

@@ -740,7 +740,7 @@ static int rm(int argc, const char **argv)
return result;
}
void clear_push_info(void *util, const char *string)
static void clear_push_info(void *util, const char *string)
{
struct push_info *info = util;
free(info->dest);
@@ -787,7 +787,7 @@ static int get_remote_ref_states(const char *name,
read_branches();
if (query) {
transport = transport_get(NULL, states->remote->url_nr > 0 ?
transport = transport_get(states->remote, states->remote->url_nr > 0 ?
states->remote->url[0] : NULL);
remote_refs = transport_get_remote_refs(transport);
transport_disconnect(transport);
@@ -815,7 +815,7 @@ struct show_info {
int any_rebase;
};
int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
static int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
{
struct show_info *info = cb_data;
int n = strlen(item->string);
@@ -825,7 +825,7 @@ int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
return 0;
}
int show_remote_info_item(struct string_list_item *item, void *cb_data)
static int show_remote_info_item(struct string_list_item *item, void *cb_data)
{
struct show_info *info = cb_data;
struct ref_states *states = info->states;
@@ -852,7 +852,7 @@ int show_remote_info_item(struct string_list_item *item, void *cb_data)
return 0;
}
int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
static int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct ref_states *states = show_info->states;
@@ -874,7 +874,7 @@ int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
return 0;
}
int show_local_info_item(struct string_list_item *item, void *cb_data)
static int show_local_info_item(struct string_list_item *item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct branch_info *branch_info = item->util;
@@ -906,7 +906,7 @@ int show_local_info_item(struct string_list_item *item, void *cb_data)
return 0;
}
int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)
static int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct push_info *push_info = push_item->util;
@@ -935,7 +935,7 @@ static int cmp_string_with_push(const void *va, const void *vb)
return cmp ? cmp : strcmp(a_push->dest, b_push->dest);
}
int show_push_info_item(struct string_list_item *item, void *cb_data)
static int show_push_info_item(struct string_list_item *item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct push_info *push_info = item->util;
@@ -999,15 +999,25 @@ static int show(int argc, const char **argv)
info.list = &info_list;
for (; argc; argc--, argv++) {
int i;
const char **url;
int url_nr;
get_remote_ref_states(*argv, &states, query_flag);
printf("* remote %s\n", *argv);
if (states.remote->url_nr) {
for (i=0; i < states.remote->url_nr; i++)
printf(" URL: %s\n", states.remote->url[i]);
} else
printf(" URL: %s\n", "(no URL)");
printf(" Fetch URL: %s\n", states.remote->url_nr > 0 ?
states.remote->url[0] : "(no URL)");
if (states.remote->pushurl_nr) {
url = states.remote->pushurl;
url_nr = states.remote->pushurl_nr;
} else {
url = states.remote->url;
url_nr = states.remote->url_nr;
}
for (i=0; i < url_nr; i++)
printf(" Push URL: %s\n", url[i]);
if (!i)
printf(" Push URL: %s\n", "(no URL)");
if (no_query)
printf(" HEAD branch: (not queried)\n");
else if (!states.heads.nr)
@@ -1187,7 +1197,7 @@ static int get_one_remote_for_update(struct remote *remote, void *priv)
return 0;
}
struct remote_group {
static struct remote_group {
const char *name;
struct string_list *list;
} remote_group;
@@ -1266,14 +1276,29 @@ static int update(int argc, const char **argv)
static int get_one_entry(struct remote *remote, void *priv)
{
struct string_list *list = priv;
struct strbuf url_buf = STRBUF_INIT;
const char **url;
int i, url_nr;
if (remote->url_nr > 0) {
int i;
for (i = 0; i < remote->url_nr; i++)
string_list_append(remote->name, list)->util = (void *)remote->url[i];
strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
string_list_append(remote->name, list)->util =
strbuf_detach(&url_buf, NULL);
} else
string_list_append(remote->name, list)->util = NULL;
if (remote->pushurl_nr) {
url = remote->pushurl;
url_nr = remote->pushurl_nr;
} else {
url = remote->url;
url_nr = remote->url_nr;
}
for (i = 0; i < url_nr; i++)
{
strbuf_addf(&url_buf, "%s (push)", url[i]);
string_list_append(remote->name, list)->util =
strbuf_detach(&url_buf, NULL);
}
return 0;
}
@@ -1281,7 +1306,10 @@ static int get_one_entry(struct remote *remote, void *priv)
static int show_all(void)
{
struct string_list list = { NULL, 0, 0 };
int result = for_each_remote(get_one_entry, &list);
int result;
list.strdup_strings = 1;
result = for_each_remote(get_one_entry, &list);
if (!result) {
int i;
@@ -1299,6 +1327,7 @@ static int show_all(void)
}
}
}
string_list_clear(&list, 1);
return result;
}

View File

@@ -301,7 +301,7 @@ static const char *skipspaces(const char *s)
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
static int keep_dashdash = 0;
static int keep_dashdash = 0, stop_at_non_option = 0;
static char const * const parseopt_usage[] = {
"git rev-parse --parseopt [options] -- [<args>...]",
NULL
@@ -309,6 +309,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
static struct option parseopt_opts[] = {
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
"keep the `--` passed as an arg"),
OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
"stop parsing after the "
"first non-option argument"),
OPT_END(),
};
@@ -394,7 +397,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
ALLOC_GROW(opts, onb + 1, osz);
memset(opts + onb, 0, sizeof(opts[onb]));
argc = parse_options(argc, argv, prefix, opts, usage,
keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 |
stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0);
strbuf_addf(&parsed, " --");
sq_quote_argv(&parsed, argv, 0);
@@ -592,7 +596,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!getcwd(cwd, PATH_MAX))
die("unable to get current working directory");
die_errno("unable to get current working directory");
printf("%s/.git\n", cwd);
continue;
}

View File

@@ -135,7 +135,7 @@ static void add_to_msg(const char *string)
{
int len = strlen(string);
if (write_in_full(msg_fd, string, len) < 0)
die ("Could not write to MERGE_MSG");
die_errno ("Could not write to MERGE_MSG");
}
static void add_message_to_msg(const char *message)

View File

@@ -257,7 +257,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
continue;
}
if (!removed)
die("git rm: %s: %s", path, strerror(errno));
die_errno("git rm: '%s'", path);
}
}

View File

@@ -59,7 +59,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
po.out = fd;
po.git_cmd = 1;
if (start_command(&po))
die("git pack-objects failed (%s)", strerror(errno));
die_errno("git pack-objects failed");
/*
* We feed the pack-objects we just spawned with revision

View File

@@ -4,12 +4,18 @@
#include "object.h"
#include "tag.h"
#include "string-list.h"
#include "parse-options.h"
static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
static const char * const show_ref_usage[] = {
"git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] ",
"git show-ref --exclude-existing[=pattern] < ref-list",
NULL
};
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
static int deref_tags, show_head, tags_only, heads_only, found_match, verify,
quiet, hash_only, abbrev, exclude_arg;
static const char **pattern;
static const char *exclude_existing_arg;
static void show_one(const char *refname, const unsigned char *sha1)
{
@@ -150,79 +156,60 @@ static int exclude_existing(const char *match)
return 0;
}
static int hash_callback(const struct option *opt, const char *arg, int unset)
{
hash_only = 1;
/* Use full length SHA1 if no argument */
if (!arg)
return 0;
return parse_opt_abbrev_cb(opt, arg, unset);
}
static int exclude_existing_callback(const struct option *opt, const char *arg,
int unset)
{
exclude_arg = 1;
*(const char **)opt->value = arg;
return 0;
}
static int help_callback(const struct option *opt, const char *arg, int unset)
{
return -1;
}
static const struct option show_ref_options[] = {
OPT_BOOLEAN(0, "tags", &tags_only, "only show tags (can be combined with heads)"),
OPT_BOOLEAN(0, "heads", &heads_only, "only show heads (can be combined with tags)"),
OPT_BOOLEAN(0, "verify", &verify, "stricter reference checking, "
"requires exact ref path"),
OPT_BOOLEAN('h', "head", &show_head, "show the HEAD reference"),
OPT_BOOLEAN('d', "dereference", &deref_tags,
"dereference tags into object IDs"),
{ OPTION_CALLBACK, 's', "hash", &abbrev, "n",
"only show SHA1 hash using <n> digits",
PARSE_OPT_OPTARG, &hash_callback },
OPT__ABBREV(&abbrev),
OPT__QUIET(&quiet),
{ OPTION_CALLBACK, 0, "exclude-existing", &exclude_existing_arg,
"pattern", "show refs from stdin that aren't in local repository",
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback },
{ OPTION_CALLBACK, 0, "help-all", NULL, NULL, "show usage",
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
int cmd_show_ref(int argc, const char **argv, const char *prefix)
{
int i;
argc = parse_options(argc, argv, prefix, show_ref_options,
show_ref_usage, PARSE_OPT_NO_INTERNAL_HELP);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (*arg != '-') {
pattern = argv + i;
break;
}
if (!strcmp(arg, "--")) {
pattern = argv + i + 1;
if (!*pattern)
pattern = NULL;
break;
}
if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet")) {
quiet = 1;
continue;
}
if (!strcmp(arg, "-h") || !strcmp(arg, "--head")) {
show_head = 1;
continue;
}
if (!strcmp(arg, "-d") || !strcmp(arg, "--dereference")) {
deref_tags = 1;
continue;
}
if (!strcmp(arg, "-s") || !strcmp(arg, "--hash")) {
hash_only = 1;
continue;
}
if (!prefixcmp(arg, "--hash=") ||
(!prefixcmp(arg, "--abbrev") &&
(arg[8] == '=' || arg[8] == '\0'))) {
if (arg[2] != 'h' && !arg[8])
/* --abbrev only */
abbrev = DEFAULT_ABBREV;
else {
/* --hash= or --abbrev= */
char *end;
if (arg[2] == 'h') {
hash_only = 1;
arg += 7;
}
else
arg += 9;
abbrev = strtoul(arg, &end, 10);
if (*end || abbrev > 40)
usage(show_ref_usage);
if (abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
}
continue;
}
if (!strcmp(arg, "--verify")) {
verify = 1;
continue;
}
if (!strcmp(arg, "--tags")) {
tags_only = 1;
continue;
}
if (!strcmp(arg, "--heads")) {
heads_only = 1;
continue;
}
if (!strcmp(arg, "--exclude-existing"))
return exclude_existing(NULL);
if (!prefixcmp(arg, "--exclude-existing="))
return exclude_existing(arg + 19);
usage(show_ref_usage);
}
if (exclude_arg)
return exclude_existing(exclude_existing_arg);
pattern = argv;
if (!*pattern)
pattern = NULL;
if (verify) {
if (!pattern)

View File

@@ -78,7 +78,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
strip_comments = 1;
if (strbuf_read(&buf, 0, 1024) < 0)
die("could not read the input");
die_errno("could not read the input");
stripspace(&buf, strip_comments);

View File

@@ -308,8 +308,7 @@ static void create_tag(const unsigned char *object, const char *tag,
path = git_pathdup("TAG_EDITMSG");
fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
die("could not create file '%s': %s",
path, strerror(errno));
die_errno("could not create file '%s'", path);
if (!is_null_sha1(prev))
write_tag_body(fd, prev);
@@ -443,11 +442,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
else {
if (!strcmp(msgfile, "-")) {
if (strbuf_read(&buf, 0, 1024) < 0)
die("cannot read %s", msgfile);
die_errno("cannot read '%s'", msgfile);
} else {
if (strbuf_read_file(&buf, msgfile, 1024) < 0)
die("could not open or read '%s': %s",
msgfile, strerror(errno));
die_errno("could not open or read '%s'",
msgfile);
}
}
}

View File

@@ -91,7 +91,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
n = write_in_full(1, content + 11, 41);
if (n < 41)
die("git get-tar-commit-id: write error");
die_errno("git get-tar-commit-id: write error");
return 0;
}

View File

@@ -68,7 +68,7 @@ static void *fill(int min)
if (ret <= 0) {
if (!ret)
die("early EOF");
die("read error on input: %s", strerror(errno));
die_errno("read error on input");
}
len += ret;
} while (len < min);
@@ -158,7 +158,7 @@ struct obj_info {
#define FLAG_WRITTEN (1u<<21)
static struct obj_info *obj_list;
unsigned nr_objects;
static unsigned nr_objects;
/*
* Called only from check_object() after it verified this object
@@ -200,7 +200,7 @@ static int check_object(struct object *obj, int type, void *data)
if (fsck_object(obj, 1, fsck_error_function))
die("Error in object");
if (!fsck_walk(obj, check_object, 0))
if (!fsck_walk(obj, check_object, NULL))
die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
write_cached_object(obj);
return 1;
@@ -210,7 +210,7 @@ static void write_rest(void)
{
unsigned i;
for (i = 0; i < nr_objects; i++)
check_object(obj_list[i].obj, OBJ_ANY, 0);
check_object(obj_list[i].obj, OBJ_ANY, NULL);
}
static void added_object(unsigned nr, enum object_type type,
@@ -422,8 +422,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
static void unpack_one(unsigned nr)
{
unsigned shift;
unsigned char *pack, c;
unsigned long size;
unsigned char *pack;
unsigned long size, c;
enum object_type type;
obj_list[nr].offset = consumed_bytes;

View File

@@ -80,16 +80,17 @@ static void error_clnt(const char *fmt, ...)
die("sent error to the client: %s", buf);
}
static void process_input(int child_fd, int band)
static ssize_t process_input(int child_fd, int band)
{
char buf[16384];
ssize_t sz = read(child_fd, buf, sizeof(buf));
if (sz < 0) {
if (errno != EAGAIN && errno != EINTR)
error_clnt("read error: %s\n", strerror(errno));
return;
return sz;
}
send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
return sz;
}
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
@@ -131,6 +132,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
while (1) {
struct pollfd pfd[2];
ssize_t processed[2] = { 0, 0 };
int status;
pfd[0].fd = fd1[0];
@@ -147,12 +149,12 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
}
if (pfd[0].revents & POLLIN)
/* Data stream ready */
process_input(pfd[0].fd, 1);
processed[0] = process_input(pfd[0].fd, 1);
if (pfd[1].revents & POLLIN)
/* Status stream ready */
process_input(pfd[1].fd, 2);
processed[1] = process_input(pfd[1].fd, 2);
/* Always finish to read data when available */
if ((pfd[0].revents | pfd[1].revents) & POLLIN)
if (processed[0] || processed[1])
continue;
if (waitpid(writer, &status, 0) < 0)

View File

@@ -13,7 +13,7 @@ static const char write_tree_usage[] =
int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
{
int missing_ok = 0, ret;
int flags = 0, ret;
const char *prefix = NULL;
unsigned char sha1[20];
const char *me = "git-write-tree";
@@ -22,9 +22,15 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--missing-ok"))
missing_ok = 1;
flags |= WRITE_TREE_MISSING_OK;
else if (!prefixcmp(arg, "--prefix="))
prefix = arg + 9;
else if (!prefixcmp(arg, "--ignore-cache-tree"))
/*
* This is only useful for debugging, so I
* do not bother documenting it.
*/
flags |= WRITE_TREE_IGNORE_CACHE_TREE;
else
usage(write_tree_usage);
argc--; argv++;
@@ -33,7 +39,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
if (argc > 2)
die("too many options");
ret = write_cache_as_tree(sha1, missing_ok, prefix);
ret = write_cache_as_tree(sha1, flags, prefix);
switch (ret) {
case 0:
printf("%s\n", sha1_to_hex(sha1));

View File

@@ -329,7 +329,8 @@ static int update_one(struct cache_tree *it,
entlen = pathlen - baselen;
}
if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))
return error("invalid object %s", sha1_to_hex(sha1));
return error("invalid object %06o %s for '%.*s'",
mode, sha1_to_hex(sha1), entlen+baselen, path);
if (ce->ce_flags & CE_REMOVE)
continue; /* entry being removed */
@@ -514,6 +515,8 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size)
static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
{
if (!it)
return NULL;
while (*path) {
const char *slash;
struct cache_tree_sub *sub;
@@ -538,28 +541,32 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
return it;
}
int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix)
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
{
int entries, was_valid, newfd;
struct lock_file *lock_file;
/*
* We can't free this memory, it becomes part of a linked list
* parsed atexit()
*/
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
entries = read_cache();
if (entries < 0)
return WRITE_TREE_UNREADABLE_INDEX;
if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
cache_tree_free(&(active_cache_tree));
if (!active_cache_tree)
active_cache_tree = cache_tree();
was_valid = cache_tree_fully_valid(active_cache_tree);
if (!was_valid) {
int missing_ok = flags & WRITE_TREE_MISSING_OK;
if (cache_tree_update(active_cache_tree,
active_cache, active_nr,
missing_ok, 0) < 0)
@@ -625,3 +632,35 @@ void prime_cache_tree(struct cache_tree **it, struct tree *tree)
*it = cache_tree();
prime_cache_tree_rec(*it, tree);
}
/*
* find the cache_tree that corresponds to the current level without
* exploding the full path into textual form. The root of the
* cache tree is given as "root", and our current level is "info".
* (1) When at root level, info->prev is NULL, so it is "root" itself.
* (2) Otherwise, find the cache_tree that corresponds to one level
* above us, and find ourselves in there.
*/
static struct cache_tree *find_cache_tree_from_traversal(struct cache_tree *root,
struct traverse_info *info)
{
struct cache_tree *our_parent;
if (!info->prev)
return root;
our_parent = find_cache_tree_from_traversal(root, info->prev);
return cache_tree_find(our_parent, info->name.path);
}
int cache_tree_matches_traversal(struct cache_tree *root,
struct name_entry *ent,
struct traverse_info *info)
{
struct cache_tree *it;
it = find_cache_tree_from_traversal(root, info);
it = cache_tree_find(it, ent->path);
if (it && it->entry_count > 0 && !hashcmp(ent->sha1, it->sha1))
return it->entry_count;
return 0;
}

View File

@@ -2,6 +2,7 @@
#define CACHE_TREE_H
#include "tree.h"
#include "tree-walk.h"
struct cache_tree;
struct cache_tree_sub {
@@ -30,11 +31,18 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
int cache_tree_fully_valid(struct cache_tree *);
int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int);
/* bitmasks to write_cache_as_tree flags */
#define WRITE_TREE_MISSING_OK 1
#define WRITE_TREE_IGNORE_CACHE_TREE 2
/* error return codes */
#define WRITE_TREE_UNREADABLE_INDEX (-1)
#define WRITE_TREE_UNMERGED_INDEX (-2)
#define WRITE_TREE_PREFIX_ERROR (-3)
int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix);
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix);
void prime_cache_tree(struct cache_tree **, struct tree *);
extern int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
#endif

13
cache.h
View File

@@ -543,7 +543,6 @@ enum rebase_setup_type {
};
enum push_default_type {
PUSH_DEFAULT_UNSPECIFIED = -1,
PUSH_DEFAULT_NOTHING = 0,
PUSH_DEFAULT_MATCHING,
PUSH_DEFAULT_TRACKING,
@@ -561,6 +560,8 @@ enum object_creation_mode {
extern enum object_creation_mode object_creation_mode;
extern int grafts_replace_parents;
#define GIT_REPO_VERSION 0
extern int repository_format_version;
extern int check_repository_format(void);
@@ -744,7 +745,17 @@ struct checkout {
};
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
struct cache_def {
char path[PATH_MAX + 1];
int len;
int flags;
int track_flags;
int prefix_len_stat_func;
};
extern int has_symlink_leading_path(const char *name, int len);
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
extern int has_symlink_or_noent_leading_path(const char *name, int len);
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
extern void invalidate_lstat_cache(const char *name, int len);

View File

@@ -80,6 +80,7 @@ struct lline {
/* Lines surviving in the merge result */
struct sline {
struct lline *lost_head, **lost_tail;
struct lline *next_lost;
char *bol;
int len;
/* bit 0 up to (N-1) are on if the parent has this line (i.e.
@@ -121,18 +122,12 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
/* Check to see if we can squash things */
if (sline->lost_head) {
struct lline *last_one = NULL;
/* We cannot squash it with earlier one */
for (lline = sline->lost_head;
lline;
lline = lline->next)
if (lline->parent_map & this_mask)
last_one = lline;
lline = last_one ? last_one->next : sline->lost_head;
lline = sline->next_lost;
while (lline) {
if (lline->len == len &&
!memcmp(lline->line, line, len)) {
lline->parent_map |= this_mask;
sline->next_lost = lline->next;
return;
}
lline = lline->next;
@@ -147,6 +142,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
lline->line[len] = 0;
*sline->lost_tail = lline;
sline->lost_tail = &lline->next;
sline->next_lost = NULL;
}
struct combine_diff_state {
@@ -168,25 +164,28 @@ static void consume_line(void *state_, char *line, unsigned long len)
&state->nb, &state->nn))
return;
state->lno = state->nb;
if (!state->nb)
/* @@ -1,2 +0,0 @@ to remove the
* first two lines...
*/
state->nb = 1;
if (state->nn == 0)
if (state->nn == 0) {
/* @@ -X,Y +N,0 @@ removed Y lines
* that would have come *after* line N
* in the result. Our lost buckets hang
* to the line after the removed lines,
*
* Note that this is correct even when N == 0,
* in which case the hunk removes the first
* line in the file.
*/
state->lost_bucket = &state->sline[state->nb];
else
if (!state->nb)
state->nb = 1;
} else {
state->lost_bucket = &state->sline[state->nb-1];
}
if (!state->sline[state->nb-1].p_lno)
state->sline[state->nb-1].p_lno =
xcalloc(state->num_parent,
sizeof(unsigned long));
state->sline[state->nb-1].p_lno[state->n] = state->ob;
state->lost_bucket->next_lost = state->lost_bucket->lost_head;
return;
}
if (!state->lost_bucket)
@@ -746,7 +745,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
done = read_in_full(fd, result, len);
if (done < 0)
die("read error '%s'", elem->path);
die_errno("read error '%s'", elem->path);
else if (done < len)
die("early EOF '%s'", elem->path);

View File

@@ -50,7 +50,6 @@ struct commit *lookup_commit(const unsigned char *sha1)
static unsigned long parse_commit_date(const char *buf, const char *tail)
{
unsigned long date;
const char *dateptr;
if (buf + 6 >= tail)
@@ -73,10 +72,7 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)
if (buf >= tail)
return 0;
/* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
date = strtoul(dateptr, NULL, 10);
if (date == ULONG_MAX)
date = 0;
return date;
return strtoul(dateptr, NULL, 10);
}
static struct commit_graft **commit_graft;
@@ -266,7 +262,11 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
bufptr[47] != '\n')
return error("bad parents in commit %s", sha1_to_hex(item->object.sha1));
bufptr += 48;
if (graft)
/*
* The clone is shallow if nr_parent < 0, and we must
* not traverse its real parents even when we unhide them.
*/
if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
continue;
new_parent = lookup_commit(parent);
if (new_parent)

View File

@@ -93,6 +93,8 @@ static inline int fcntl(int fd, int cmd, long arg)
errno = EINVAL;
return -1;
}
/* bash cannot reliably detect negative return codes as failure */
#define exit(code) exit((code) & 0xff)
/*
* simple adaptors

View File

@@ -1174,7 +1174,9 @@ write_err_out:
static int section_name_match (const char *buf, const char *name)
{
int i = 0, j = 0, dot = 0;
for (; buf[i] && buf[i] != ']'; i++) {
if (buf[i] != '[')
return 0;
for (i = 1; buf[i] && buf[i] != ']'; i++) {
if (!dot && isspace(buf[i])) {
dot = 1;
if (name[j++] != '.')
@@ -1195,7 +1197,17 @@ static int section_name_match (const char *buf, const char *name)
if (buf[i] != name[j++])
break;
}
return (buf[i] == ']' && name[j] == 0);
if (buf[i] == ']' && name[j] == 0) {
/*
* We match, now just find the right length offset by
* gobbling up any whitespace after it, as well
*/
i++;
for (; buf[i] && isspace(buf[i]); i++)
; /* do nothing */
return i;
}
return 0;
}
/* if new_name == NULL, the section is removed instead */
@@ -1225,11 +1237,13 @@ int git_config_rename_section(const char *old_name, const char *new_name)
while (fgets(buf, sizeof(buf), config_file)) {
int i;
int length;
char *output = buf;
for (i = 0; buf[i] && isspace(buf[i]); i++)
; /* do nothing */
if (buf[i] == '[') {
/* it's a section */
if (section_name_match (&buf[i+1], old_name)) {
int offset = section_name_match(&buf[i], old_name);
if (offset > 0) {
ret++;
if (new_name == NULL) {
remove = 1;
@@ -1240,14 +1254,29 @@ int git_config_rename_section(const char *old_name, const char *new_name)
ret = write_error(lock->filename);
goto out;
}
continue;
/*
* We wrote out the new section, with
* a newline, now skip the old
* section's length
*/
output += offset + i;
if (strlen(output) > 0) {
/*
* More content means there's
* a declaration to put on the
* next line; indent with a
* tab
*/
output -= 1;
output[0] = '\t';
}
}
remove = 0;
}
if (remove)
continue;
length = strlen(buf);
if (write_in_full(out_fd, buf, length) != length) {
length = strlen(output);
if (write_in_full(out_fd, output, length) != length) {
ret = write_error(lock->filename);
goto out;
}

View File

@@ -34,6 +34,7 @@ NO_LIBGEN_H=@NO_LIBGEN_H@
NEEDS_LIBICONV=@NEEDS_LIBICONV@
NEEDS_SOCKET=@NEEDS_SOCKET@
NEEDS_RESOLV=@NEEDS_RESOLV@
NEEDS_LIBGEN=@NEEDS_LIBGEN@
NO_SYS_SELECT_H=@NO_SYS_SELECT_H@
NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@

View File

@@ -342,9 +342,8 @@ GIT_STASH_FLAGS($OPENSSLDIR)
AC_CHECK_LIB([crypto], [SHA1_Init],
[NEEDS_SSL_WITH_CRYPTO=],
[AC_CHECK_LIB([ssl], [SHA1_Init],
[NEEDS_SSL_WITH_CRYPTO=YesPlease
NEEDS_SSL_WITH_CRYPTO=],
[NO_OPENSSL=YesPlease])])
[NEEDS_SSL_WITH_CRYPTO=YesPlease],
[NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])])
GIT_UNSTASH_FLAGS($OPENSSLDIR)
@@ -385,6 +384,8 @@ AC_SUBST(NO_EXPAT)
# some Solaris installations).
# Define NO_ICONV if neither libc nor libiconv support iconv.
if test -z "$NO_ICONV"; then
GIT_STASH_FLAGS($ICONVDIR)
AC_DEFUN([ICONVTEST_SRC], [
@@ -431,6 +432,12 @@ GIT_UNSTASH_FLAGS($ICONVDIR)
AC_SUBST(NEEDS_LIBICONV)
AC_SUBST(NO_ICONV)
if test -n "$NO_ICONV"; then
NEEDS_LIBICONV=
fi
fi
#
# Define NO_DEFLATE_BOUND if deflateBound is missing from zlib.
@@ -471,12 +478,18 @@ test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
# Define NEEDS_RESOLV if linking with -lnsl and/or -lsocket is not enough.
# Notably on Solaris hstrerror resides in libresolv and on Solaris 7
# inet_ntop and inet_pton additionally reside there.
AC_CHECK_LIB([resolv], [hstrerror],
AC_CHECK_LIB([c], [hstrerror],
[NEEDS_RESOLV=],
[NEEDS_RESOLV=YesPlease])
AC_SUBST(NEEDS_RESOLV)
test -n "$NEEDS_RESOLV" && LIBS="$LIBS -lresolv"
AC_CHECK_LIB([c], [basename],
[NEEDS_LIBGEN=],
[NEEDS_LIBGEN=YesPlease])
AC_SUBST(NEEDS_LIBGEN)
test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen"
## Checks for header files.
AC_MSG_NOTICE([CHECKS for header files])
#

View File

@@ -464,7 +464,7 @@ static void git_proxy_connect(int fd[2], char *host)
#define MAX_CMD_LEN 1024
char *get_port(char *host)
static char *get_port(char *host)
{
char *end;
char *p = strchr(host, ':');

View File

@@ -44,6 +44,10 @@
# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
# then a '$' will be shown next to the branch name.
#
# If you would like to see if there're untracked files, then you can
# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
# untracked files, then a '%' will be shown next to the branch name.
#
# To submit patches:
#
# *) Read Documentation/SubmittingPatches
@@ -132,6 +136,7 @@ __git_ps1 ()
local w
local i
local s
local u
local c
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
@@ -156,12 +161,18 @@ __git_ps1 ()
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
fi
if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
u="%"
fi
fi
fi
if [ -n "${1-}" ]; then
printf "$1" "$c${b##refs/heads/}$w$i$s$r"
printf "$1" "$c${b##refs/heads/}$w$i$s$u$r"
else
printf " (%s)" "$c${b##refs/heads/}$w$i$s$r"
printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r"
fi
fi
}
@@ -1114,7 +1125,7 @@ _git_ls_tree ()
__git_log_common_options="
--not --all
--branches --tags --remotes
--first-parent --no-merges
--first-parent --merges --no-merges
--max-count=
--max-age= --since= --after=
--min-age= --until= --before=
@@ -1165,7 +1176,7 @@ _git_log ()
$__git_log_shortlog_options
$__git_log_gitk_options
--root --topo-order --date-order --reverse
--follow
--follow --full-diff
--abbrev-commit --abbrev=
--relative-date --date=
--pretty= --format= --oneline
@@ -1299,7 +1310,7 @@ _git_rebase ()
}
__git_send_email_confirm_options="always never auto cc compose"
__git_send_email_suppresscc_options="author self cc ccbody sob cccmd body all"
__git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
_git_send_email ()
{
@@ -1357,11 +1368,12 @@ __git_config_get_set_variables ()
c=$((--c))
done
for i in $(git --git-dir="$(__gitdir)" config $config_file --list \
2>/dev/null); do
case "$i" in
*.*)
echo "${i/=*/}"
git --git-dir="$(__gitdir)" config $config_file --list 2>/dev/null |
while read line
do
case "$line" in
*.*=*)
echo "${line/=*/}"
;;
esac
done
@@ -1457,7 +1469,7 @@ _git_config ()
branch.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
__gitcomp "remote merge mergeoptions" "$pfx" "$cur"
__gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur"
return
;;
branch.*)
@@ -1504,7 +1516,7 @@ _git_config ()
cur="${cur##*.}"
__gitcomp "
url proxy fetch push mirror skipDefaultUpdate
receivepack uploadpack tagopt
receivepack uploadpack tagopt pushurl
" "$pfx" "$cur"
return
;;
@@ -1522,6 +1534,7 @@ _git_config ()
;;
esac
__gitcomp "
add.ignore-errors
alias.
apply.whitespace
branch.autosetupmerge

View File

@@ -26,7 +26,7 @@ static void flush(struct sha1file *f, void * buf, unsigned int count)
}
if (!ret)
die("sha1 file '%s' write error. Out of diskspace", f->name);
die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
die_errno("sha1 file '%s' write error", f->name);
}
}
@@ -55,8 +55,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
if (flags & CSUM_FSYNC)
fsync_or_die(f->fd, f->name);
if (close(f->fd))
die("%s: sha1 file error on close (%s)",
f->name, strerror(errno));
die_errno("%s: sha1 file error on close", f->name);
fd = 0;
} else
fd = f->fd;

View File

@@ -1,6 +1,8 @@
#include "cache.h"
#include "pkt-line.h"
#include "exec_cmd.h"
#include "run-command.h"
#include "strbuf.h"
#include <syslog.h>
@@ -343,28 +345,66 @@ static int run_service(char *dir, struct daemon_service *service)
return service->fn();
}
static void copy_to_log(int fd)
{
struct strbuf line = STRBUF_INIT;
FILE *fp;
fp = fdopen(fd, "r");
if (fp == NULL) {
logerror("fdopen of error channel failed");
close(fd);
return;
}
while (strbuf_getline(&line, fp, '\n') != EOF) {
logerror("%s", line.buf);
strbuf_setlen(&line, 0);
}
strbuf_release(&line);
fclose(fp);
}
static int run_service_command(const char **argv)
{
struct child_process cld;
memset(&cld, 0, sizeof(cld));
cld.argv = argv;
cld.git_cmd = 1;
cld.err = -1;
if (start_command(&cld))
return -1;
close(0);
close(1);
copy_to_log(cld.err);
return finish_command(&cld);
}
static int upload_pack(void)
{
/* Timeout as string */
char timeout_buf[64];
const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL };
snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
/* git-upload-pack only ever reads stuff, so this is safe */
execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
return -1;
return run_service_command(argv);
}
static int upload_archive(void)
{
execl_git_cmd("upload-archive", ".", NULL);
return -1;
static const char *argv[] = { "upload-archive", ".", NULL };
return run_service_command(argv);
}
static int receive_pack(void)
{
execl_git_cmd("receive-pack", ".", NULL);
return -1;
static const char *argv[] = { "receive-pack", ".", NULL };
return run_service_command(argv);
}
static struct daemon_service daemon_service[] = {
@@ -453,7 +493,7 @@ static void parse_host_arg(char *extra_args, int buflen)
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
gai = getaddrinfo(hostname, 0, &hints, &ai);
gai = getaddrinfo(hostname, NULL, &hints, &ai);
if (!gai) {
struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
@@ -862,7 +902,7 @@ static int service_loop(int socknum, int *socklist)
case ECONNABORTED:
continue;
default:
die("accept returned %s", strerror(errno));
die_errno("accept returned");
}
}
handle(incoming, (struct sockaddr *)&ss, sslen);
@@ -878,7 +918,7 @@ static void sanitize_stdfds(void)
while (fd != -1 && fd < 2)
fd = dup(fd);
if (fd == -1)
die("open /dev/null or dup failed: %s", strerror(errno));
die_errno("open /dev/null or dup failed");
if (fd > 2)
close(fd);
}
@@ -889,12 +929,12 @@ static void daemonize(void)
case 0:
break;
case -1:
die("fork failed: %s", strerror(errno));
die_errno("fork failed");
default:
exit(0);
}
if (setsid() == -1)
die("setsid failed: %s", strerror(errno));
die_errno("setsid failed");
close(0);
close(1);
close(2);
@@ -905,9 +945,9 @@ static void store_pid(const char *path)
{
FILE *f = fopen(path, "w");
if (!f)
die("cannot open pid file %s: %s", path, strerror(errno));
die_errno("cannot open pid file '%s'", path);
if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0)
die("failed to write pid file %s: %s", path, strerror(errno));
die_errno("failed to write pid file '%s'", path);
}
static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
@@ -1107,8 +1147,7 @@ int main(int argc, char **argv)
socklen_t slen = sizeof(ss);
if (!freopen("/dev/null", "w", stderr))
die("failed to redirect stderr to /dev/null: %s",
strerror(errno));
die_errno("failed to redirect stderr to /dev/null");
if (getpeername(0, peer, &slen))
peer = NULL;

View File

@@ -90,12 +90,11 @@ static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
const unsigned char *top)
{
const unsigned char *data = *datap;
unsigned char cmd;
unsigned long size = 0;
unsigned long cmd, size = 0;
int i = 0;
do {
cmd = *data++;
size |= (cmd & ~0x80) << i;
size |= (cmd & 0x7f) << i;
i += 7;
} while (cmd & 0x80 && data < top);
*datap = data;

View File

@@ -446,6 +446,8 @@ int run_diff_index(struct rev_info *revs, int cached)
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
opts.index_only = cached;
opts.diff_index_cached = (cached &&
!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER));
opts.merge = 1;
opts.fn = oneway_diff;
opts.unpack_data = revs;
@@ -502,6 +504,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
opts.index_only = 1;
opts.diff_index_cached = !DIFF_OPT_TST(opt, FIND_COPIES_HARDER);
opts.merge = 1;
opts.fn = oneway_diff;
opts.unpack_data = &revs;

11
diff.c
View File

@@ -1603,6 +1603,7 @@ static void builtin_diff(const char *name_a,
free(mf1.ptr);
if (textconv_two)
free(mf2.ptr);
xdiff_clear_find_func(&xecfg);
}
free_ab_and_return:
@@ -1975,14 +1976,14 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf,
strlen(base) + 1);
if (fd < 0)
die("unable to create temp-file: %s", strerror(errno));
die_errno("unable to create temp-file");
if (convert_to_working_tree(path,
(const char *)blob, (size_t)size, &buf)) {
blob = buf.buf;
size = buf.len;
}
if (write_in_full(fd, blob, size) != size)
die("unable to write temp-file");
die_errno("unable to write temp-file");
close(fd);
temp->name = temp->tmp_path;
strcpy(temp->hex, sha1_to_hex(sha1));
@@ -2021,12 +2022,12 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
if (lstat(name, &st) < 0) {
if (errno == ENOENT)
goto not_a_valid_file;
die("stat(%s): %s", name, strerror(errno));
die_errno("stat(%s)", name);
}
if (S_ISLNK(st.st_mode)) {
struct strbuf sb = STRBUF_INIT;
if (strbuf_readlink(&sb, name, st.st_size) < 0)
die("readlink(%s)", name);
die_errno("readlink(%s)", name);
prep_temp_blob(name, temp, sb.buf, sb.len,
(one->sha1_valid ?
one->sha1 : null_sha1),
@@ -2219,7 +2220,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
return;
}
if (lstat(one->path, &st) < 0)
die("stat %s", one->path);
die_errno("stat '%s'", one->path);
if (index_path(one->sha1, one->path, &st, 0))
die("cannot hash %s", one->path);
}

113
dir.c
View File

@@ -14,12 +14,11 @@ struct path_simplify {
const char *path;
};
static int read_directory_recursive(struct dir_struct *dir,
const char *path, const char *base, int baselen,
static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
int check_only, const struct path_simplify *simplify);
static int get_dtype(struct dirent *de, const char *path);
static int get_dtype(struct dirent *de, const char *path, int len);
int common_prefix(const char **pathspec)
static int common_prefix(const char **pathspec)
{
const char *path, *slash, *next;
int prefix;
@@ -52,6 +51,26 @@ int common_prefix(const char **pathspec)
return prefix;
}
int fill_directory(struct dir_struct *dir, const char **pathspec)
{
const char *path;
int len;
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
len = common_prefix(pathspec);
path = "";
if (len)
path = xmemdupz(*pathspec, len);
/* Read the directory and prune it */
read_directory(dir, path, len, pathspec);
return len;
}
/*
* Does 'match' match the given name?
* A match is found if
@@ -307,7 +326,7 @@ static int excluded_1(const char *pathname,
if (x->flags & EXC_FLAG_MUSTBEDIR) {
if (*dtype == DT_UNKNOWN)
*dtype = get_dtype(NULL, pathname);
*dtype = get_dtype(NULL, pathname, pathlen);
if (*dtype != DT_DIR)
continue;
}
@@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
/* This is the "show_other_directories" case */
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
return show_directory;
if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
if (!read_directory_recursive(dir, dirname, len, 1, simplify))
return ignore_directory;
return show_directory;
}
@@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
return 0;
}
static int get_dtype(struct dirent *de, const char *path)
static int get_index_dtype(const char *path, int len)
{
int pos;
struct cache_entry *ce;
ce = cache_name_exists(path, len, 0);
if (ce) {
if (!ce_uptodate(ce))
return DT_UNKNOWN;
if (S_ISGITLINK(ce->ce_mode))
return DT_DIR;
/*
* Nobody actually cares about the
* difference between DT_LNK and DT_REG
*/
return DT_REG;
}
/* Try to look it up as a directory */
pos = cache_name_pos(path, len);
if (pos >= 0)
return DT_UNKNOWN;
pos = -pos-1;
while (pos < active_nr) {
ce = active_cache[pos++];
if (strncmp(ce->name, path, len))
break;
if (ce->name[len] > '/')
break;
if (ce->name[len] < '/')
continue;
if (!ce_uptodate(ce))
break; /* continue? */
return DT_DIR;
}
return DT_UNKNOWN;
}
static int get_dtype(struct dirent *de, const char *path, int len)
{
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st;
if (dtype != DT_UNKNOWN)
return dtype;
dtype = get_index_dtype(path, len);
if (dtype != DT_UNKNOWN)
return dtype;
if (lstat(path, &st))
@@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path)
* Also, we ignore the name ".git" (even if it is not a directory).
* That likely will not change.
*/
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
{
DIR *fdir = opendir(*path ? path : ".");
DIR *fdir = opendir(*base ? base : ".");
int contents = 0;
if (fdir) {
struct dirent *de;
char fullname[PATH_MAX + 1];
memcpy(fullname, base, baselen);
char path[PATH_MAX + 1];
memcpy(path, base, baselen);
while ((de = readdir(fdir)) != NULL) {
int len, dtype;
@@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;
len = strlen(de->d_name);
/* Ignore overly long pathnames! */
if (len + baselen + 8 > sizeof(fullname))
if (len + baselen + 8 > sizeof(path))
continue;
memcpy(fullname + baselen, de->d_name, len+1);
if (simplify_away(fullname, baselen + len, simplify))
memcpy(path + baselen, de->d_name, len+1);
len = baselen + len;
if (simplify_away(path, len, simplify))
continue;
dtype = DTYPE(de);
exclude = excluded(dir, fullname, &dtype);
exclude = excluded(dir, path, &dtype);
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
&& in_pathspec(fullname, baselen + len, simplify))
dir_add_ignored(dir, fullname, baselen + len);
&& in_pathspec(path, len, simplify))
dir_add_ignored(dir, path,len);
/*
* Excluded? If we don't explicitly want to show
@@ -613,7 +674,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;
if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, fullname);
dtype = get_dtype(de, path, len);
/*
* Do we want to see just the ignored files?
@@ -630,9 +691,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
default:
continue;
case DT_DIR:
memcpy(fullname + baselen + len, "/", 2);
memcpy(path + len, "/", 2);
len++;
switch (treat_directory(dir, fullname, baselen + len, simplify)) {
switch (treat_directory(dir, path, len, simplify)) {
case show_directory:
if (exclude != !!(dir->flags
& DIR_SHOW_IGNORED))
@@ -640,7 +701,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
break;
case recurse_into_directory:
contents += read_directory_recursive(dir,
fullname, fullname, baselen + len, 0, simplify);
path, len, 0, simplify);
continue;
case ignore_directory:
continue;
@@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
if (check_only)
goto exit_early;
else
dir_add_name(dir, fullname, baselen + len);
dir_add_name(dir, path, len);
}
exit_early:
closedir(fdir);
@@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify)
free(simplify);
}
int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
{
struct path_simplify *simplify;
if (has_symlink_leading_path(path, strlen(path)))
if (has_symlink_leading_path(path, len))
return dir->nr;
simplify = create_simplify(pathspec);
read_directory_recursive(dir, path, base, baselen, 0, simplify);
read_directory_recursive(dir, path, len, 0, simplify);
free_simplify(simplify);
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
@@ -759,7 +820,7 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
if (!dir)
return NULL;
if (!getcwd(buffer, size))
die("can't find the current directory: %s", strerror(errno));
die_errno("can't find the current directory");
if (!is_absolute_path(dir))
dir = make_absolute_path(dir);

5
dir.h
View File

@@ -61,14 +61,13 @@ struct dir_struct {
char basebuf[PATH_MAX];
};
extern int common_prefix(const char **pathspec);
#define MATCHED_RECURSIVELY 1
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
extern int fill_directory(struct dir_struct *dir, const char **pathspec);
extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
extern int excluded(struct dir_struct *, const char *, int *);
extern void add_excludes_from_file(struct dir_struct *, const char *fname);

10
entry.c
View File

@@ -37,7 +37,7 @@ static void create_directories(const char *path, int path_len,
if (errno == EEXIST && state->force &&
!unlink_or_warn(buf) && !mkdir(buf, 0777))
continue;
die("cannot create directory at %s", buf);
die_errno("cannot create directory at '%s'", buf);
}
}
free(buf);
@@ -51,7 +51,7 @@ static void remove_subtree(const char *path)
char *name;
if (!dir)
die("cannot opendir %s (%s)", path, strerror(errno));
die_errno("cannot opendir '%s'", path);
strcpy(pathbuf, path);
name = pathbuf + strlen(path);
*name++ = '/';
@@ -61,15 +61,15 @@ static void remove_subtree(const char *path)
continue;
strcpy(name, de->d_name);
if (lstat(pathbuf, &st))
die("cannot lstat %s (%s)", pathbuf, strerror(errno));
die_errno("cannot lstat '%s'", pathbuf);
if (S_ISDIR(st.st_mode))
remove_subtree(pathbuf);
else if (unlink(pathbuf))
die("cannot unlink %s (%s)", pathbuf, strerror(errno));
die_errno("cannot unlink '%s'", pathbuf);
}
closedir(dir);
if (rmdir(path))
die("cannot rmdir %s (%s)", path, strerror(errno));
die_errno("cannot rmdir '%s'", path);
}
static int create_file(const char *path, unsigned int mode)

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