mirror of
https://github.com/git/git.git
synced 2026-04-01 20:40:08 +02:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,2 +1,3 @@
|
||||
* whitespace=!indent,trail,space
|
||||
*.[ch] whitespace=indent,trail,space
|
||||
*.sh whitespace=indent,trail,space
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
/GIT-CFLAGS
|
||||
/GIT-GUI-VARS
|
||||
/GIT-VERSION-FILE
|
||||
/bin-wrappers/
|
||||
/git
|
||||
/git-add
|
||||
/git-add--interactive
|
||||
|
||||
15
Documentation/RelNotes-1.6.6.1.txt
Normal file
15
Documentation/RelNotes-1.6.6.1.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Git v1.6.6.1 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.6.6
|
||||
------------------
|
||||
|
||||
* http-backend was not listed in the command list in the documentation.
|
||||
|
||||
Other minor documentation updates are included.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.6.6-4-gd828fdb
|
||||
echo O=$(git describe maint)
|
||||
git shortlog --no-merges $O..maint
|
||||
70
Documentation/RelNotes-1.7.0.txt
Normal file
70
Documentation/RelNotes-1.7.0.txt
Normal file
@@ -0,0 +1,70 @@
|
||||
Git v1.7.0 Release Notes
|
||||
========================
|
||||
|
||||
Notes on behaviour change
|
||||
-------------------------
|
||||
|
||||
* "git push" into a branch that is currently checked out (i.e. pointed by
|
||||
HEAD in a repository that is not bare) is refused by default.
|
||||
|
||||
Similarly, "git push $there :$killed" to delete the branch $killed
|
||||
in a remote repository $there, when $killed branch is the current
|
||||
branch pointed at by its HEAD, will be refused by default.
|
||||
|
||||
Setting the configuration variables receive.denyCurrentBranch and
|
||||
receive.denyDeleteCurrent to 'ignore' in the receiving repository
|
||||
can be used to override these safety features.
|
||||
|
||||
* "git send-email" does not make deep threads by default when sending a
|
||||
patch series with more than two messages. All messages will be sent
|
||||
as a reply to the first message, i.e. cover letter.
|
||||
|
||||
It has been possible to configure send-email to send "shallow thread"
|
||||
by setting sendemail.chainreplyto configuration variable to false. The
|
||||
only thing this release does is to change the default when you haven't
|
||||
configured that variable.
|
||||
|
||||
* "git status" is not "git commit --dry-run" anymore. This change does
|
||||
not affect you if you run the command without pathspec.
|
||||
|
||||
* "git diff" traditionally treated various "ignore whitespace" options
|
||||
only as a way to filter the patch output. "git diff --exit-code -b"
|
||||
exited with non-zero status even if all changes were about changing the
|
||||
ammount of whitespace and nothing else. and "git diff -b" showed the
|
||||
"diff --git" header line for such a change without patch text.
|
||||
|
||||
In this release, the "ignore whitespaces" options affect the semantics
|
||||
of the diff operation. A change that does not affect anything but
|
||||
whitespaces is reported with zero exit status when run with
|
||||
--exit-code, and there is no "diff --git" header for such a change.
|
||||
|
||||
|
||||
Updates since v1.6.6
|
||||
--------------------
|
||||
|
||||
(subsystems)
|
||||
|
||||
(portability)
|
||||
|
||||
(performance)
|
||||
|
||||
(usability, bells and whistles)
|
||||
|
||||
* "git commit --date='<date>'" can be used to override the author date
|
||||
just like "git commit --author='<name> <email>'" can be used to
|
||||
override the author identity.
|
||||
|
||||
* "git status" learned "-s(hort)" output format.
|
||||
|
||||
|
||||
Fixes since v1.6.6
|
||||
------------------
|
||||
|
||||
All of the fixes in v1.6.6.X maintenance series are included in this
|
||||
release, unless otherwise noted.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.6.6-101-gf012d27
|
||||
echo O=$(git describe master)
|
||||
git shortlog --no-merges $O..master ^maint
|
||||
@@ -279,6 +279,20 @@ from the list and queue it to 'pu', in order to make it easier for
|
||||
people play with it without having to pick up and apply the patch to
|
||||
their trees themselves.
|
||||
|
||||
------------------------------------------------
|
||||
Know the status of your patch after submission
|
||||
|
||||
* You can use Git itself to find out when your patch is merged in
|
||||
master. 'git pull --rebase' will automatically skip already-applied
|
||||
patches, and will let you know. This works only if you rebase on top
|
||||
of the branch in which your patch has been merged (i.e. it will not
|
||||
tell you if your patch is merged in pu if you rebase on top of
|
||||
master).
|
||||
|
||||
* Read the git mailing list, the maintainer regularly posts messages
|
||||
entitled "What's cooking in git.git" and "What's in git.git" giving
|
||||
the status of various proposed changes.
|
||||
|
||||
------------------------------------------------
|
||||
MUA specific hints
|
||||
|
||||
|
||||
@@ -297,17 +297,24 @@ false), while all other repositories are assumed to be bare (bare
|
||||
= true).
|
||||
|
||||
core.worktree::
|
||||
Set the path to the working tree. The value will not be
|
||||
used in combination with repositories found automatically in
|
||||
a .git directory (i.e. $GIT_DIR is not set).
|
||||
Set the path to the root of the work tree.
|
||||
This can be overridden by the GIT_WORK_TREE environment
|
||||
variable and the '--work-tree' command line option. It can be
|
||||
a absolute path or relative path to the directory specified by
|
||||
--git-dir or GIT_DIR.
|
||||
Note: If --git-dir or GIT_DIR are specified but none of
|
||||
an absolute path or a relative path to the .git directory,
|
||||
either specified by --git-dir or GIT_DIR, or automatically
|
||||
discovered.
|
||||
If --git-dir or GIT_DIR are specified but none of
|
||||
--work-tree, GIT_WORK_TREE and core.worktree is specified,
|
||||
the current working directory is regarded as the top directory
|
||||
of your working tree.
|
||||
the current working directory is regarded as the root of the
|
||||
work tree.
|
||||
+
|
||||
Note that this variable is honored even when set in a configuration
|
||||
file in a ".git" subdirectory of a directory, and its value differs
|
||||
from the latter directory (e.g. "/path/to/.git/config" has
|
||||
core.worktree set to "/different/path"), which is most likely a
|
||||
misconfiguration. Running git commands in "/path/to" directory will
|
||||
still use "/different/path" as the root of the work tree and can cause
|
||||
great confusion to the users.
|
||||
|
||||
core.logAllRefUpdates::
|
||||
Enable the reflog. Updates to a ref <ref> is logged to the file
|
||||
@@ -530,7 +537,7 @@ apply.whitespace::
|
||||
as the '--whitespace' option. See linkgit:git-apply[1].
|
||||
|
||||
branch.autosetupmerge::
|
||||
Tells 'git-branch' and 'git-checkout' to setup new branches
|
||||
Tells 'git-branch' and 'git-checkout' to set up new branches
|
||||
so that linkgit:git-pull[1] will appropriately merge from the
|
||||
starting point branch. Note that even if this option is not set,
|
||||
this behavior can be chosen per-branch using the `--track`
|
||||
@@ -718,7 +725,7 @@ diff.autorefreshindex::
|
||||
contents in the work tree match the contents in the
|
||||
index. This option defaults to true. Note that this
|
||||
affects only 'git-diff' Porcelain, and not lower level
|
||||
'diff' commands, such as 'git-diff-files'.
|
||||
'diff' commands such as 'git-diff-files'.
|
||||
|
||||
diff.external::
|
||||
If this config variable is set, diff generation is not
|
||||
@@ -834,8 +841,8 @@ format.pretty::
|
||||
|
||||
format.thread::
|
||||
The default threading style for 'git-format-patch'. Can be
|
||||
either a boolean value, `shallow` or `deep`. `shallow`
|
||||
threading makes every mail a reply to the head of the series,
|
||||
a boolean value, or `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.
|
||||
@@ -868,15 +875,12 @@ gc.autopacklimit::
|
||||
default value is 50. Setting this to 0 disables it.
|
||||
|
||||
gc.packrefs::
|
||||
'git-gc' does not run `git pack-refs` in a bare repository by
|
||||
default so that older dumb-transport clients can still fetch
|
||||
from the repository. Setting this to `true` lets 'git-gc'
|
||||
to run `git pack-refs`. Setting this to `false` tells
|
||||
'git-gc' never to run `git pack-refs`. The default setting is
|
||||
`notbare`. Enable it only when you know you do not have to
|
||||
support such clients. The default setting will change to `true`
|
||||
at some stage, and setting this to `false` will continue to
|
||||
prevent `git pack-refs` from being run from 'git-gc'.
|
||||
Running `git pack-refs` in a repository renders it
|
||||
unclonable by Git versions prior to 1.5.1.2 over dumb
|
||||
transports such as HTTP. This variable determines whether
|
||||
'git gc' runs `git pack-refs`. This can be set to "nobare"
|
||||
to enable it within all non-bare repos or it can be set to a
|
||||
boolean value. The default is `true`.
|
||||
|
||||
gc.pruneexpire::
|
||||
When 'git-gc' is run, it will call 'prune --expire 2.weeks.ago'.
|
||||
@@ -1132,6 +1136,12 @@ http.maxRequests::
|
||||
How many HTTP requests to launch in parallel. Can be overridden
|
||||
by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
|
||||
|
||||
http.minSessions::
|
||||
The number of curl sessions (counted across slots) to be kept across
|
||||
requests. They will not be ended with curl_easy_cleanup() until
|
||||
http_cleanup() is invoked. If USE_CURL_MULTI is not defined, this
|
||||
value will be capped at 1. Defaults to 1.
|
||||
|
||||
http.postBuffer::
|
||||
Maximum size in bytes of the buffer used by smart HTTP
|
||||
transports when POSTing data to the remote system.
|
||||
@@ -1461,6 +1471,10 @@ remote.<name>.tagopt::
|
||||
Setting this value to \--no-tags disables automatic tag following when
|
||||
fetching from remote <name>
|
||||
|
||||
remote.<name>.vcs::
|
||||
Setting this to a value <vcs> will cause git to interact with
|
||||
the remote with the git-remote-<vcs> helper.
|
||||
|
||||
remotes.<group>::
|
||||
The list of remotes which are fetched by "git remote update
|
||||
<group>". See linkgit:git-remote[1].
|
||||
|
||||
26
Documentation/date-formats.txt
Normal file
26
Documentation/date-formats.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
DATE FORMATS
|
||||
------------
|
||||
|
||||
The GIT_AUTHOR_DATE, GIT_COMMITTER_DATE environment variables
|
||||
ifdef::git-commit[]
|
||||
and the `--date` option
|
||||
endif::git-commit[]
|
||||
support the following date formats:
|
||||
|
||||
Git internal format::
|
||||
It is `<unix timestamp> <timezone offset>`, where `<unix
|
||||
timestamp>` is the number of seconds since the UNIX epoch.
|
||||
`<timezone offset>` is a positive or negative offset from UTC.
|
||||
For example CET (which is 2 hours ahead UTC) is `+0200`.
|
||||
|
||||
RFC 2822::
|
||||
The standard email format as described by RFC 2822, for example
|
||||
`Thu, 07 Apr 2005 22:13:13 +0200`.
|
||||
|
||||
ISO 8601::
|
||||
Time and date specified by the ISO 8601 standard, for example
|
||||
`2005-04-07T22:13:13`. The parser accepts a space instead of the
|
||||
`T` character as well.
|
||||
+
|
||||
NOTE: In addition, the date part is accepted in the following formats:
|
||||
`YYYY.MM.DD`, `MM/DD/YYYY` and `DD.MM.YYYY`.
|
||||
@@ -14,28 +14,32 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This command adds the current content of new or modified files to the
|
||||
index, thus staging that content for inclusion in the next commit.
|
||||
This command updates the index using the current content found in
|
||||
the working tree, to prepare the content staged for the next commit.
|
||||
It typically adds the current content of existing paths as a whole,
|
||||
but with some options it can also be used to add content with
|
||||
only part of the changes made to the working tree files applied, or
|
||||
remove paths that do not exist in the working tree anymore.
|
||||
|
||||
The "index" holds a snapshot of the content of the working tree, and it
|
||||
is this snapshot that is taken as the contents of the next commit. Thus
|
||||
after making any changes to the working directory, and before running
|
||||
the commit command, you must use the 'add' command to add any new or
|
||||
the commit command, you must use the `add` command to add any new or
|
||||
modified files to the index.
|
||||
|
||||
This command can be performed multiple times before a commit. It only
|
||||
adds the content of the specified file(s) at the time the add command is
|
||||
run; if you want subsequent changes included in the next commit, then
|
||||
you must run 'git add' again to add the new content to the index.
|
||||
you must run `git add` again to add the new content to the index.
|
||||
|
||||
The 'git status' command can be used to obtain a summary of which
|
||||
The `git status` command can be used to obtain a summary of which
|
||||
files have changes that are staged for the next commit.
|
||||
|
||||
The 'git add' command will not add ignored files by default. If any
|
||||
ignored files were explicitly specified on the command line, 'git add'
|
||||
The `git add` command will not add ignored files by default. If any
|
||||
ignored files were explicitly specified on the command line, `git add`
|
||||
will fail with a list of ignored files. Ignored files reached by
|
||||
directory recursion or filename globbing performed by Git (quote your
|
||||
globs before the shell) will be silently ignored. The 'add' command can
|
||||
globs before the shell) will be silently ignored. The `add` command can
|
||||
be used to add ignored files with the `-f` (force) option.
|
||||
|
||||
Please see linkgit:git-commit[1] for alternative ways to add content to a
|
||||
@@ -92,28 +96,31 @@ apply.
|
||||
|
||||
-u::
|
||||
--update::
|
||||
Update only files that git already knows about, staging modified
|
||||
content for commit and marking deleted files for removal. This
|
||||
is similar
|
||||
to what "git commit -a" does in preparation for making a commit,
|
||||
except that the update is limited to paths specified on the
|
||||
command line. If no paths are specified, all tracked files in the
|
||||
current directory and its subdirectories are updated.
|
||||
Only match <filepattern> against already tracked files in
|
||||
the index rather than the working tree. That means that it
|
||||
will never stage new files, but that it will stage modified
|
||||
new contents of tracked files and that it will remove files
|
||||
from the index if the corresponding files in the working tree
|
||||
have been removed.
|
||||
+
|
||||
If no <filepattern> is given, default to "."; in other words,
|
||||
update all tracked files in the current directory and its
|
||||
subdirectories.
|
||||
|
||||
-A::
|
||||
--all::
|
||||
Update files that git already knows about (same as '\--update')
|
||||
and add all untracked files that are not ignored by '.gitignore'
|
||||
mechanism.
|
||||
|
||||
Like `-u`, but match <filepattern> against files in the
|
||||
working tree in addition to the index. That means that it
|
||||
will find new files as well as staging modified content and
|
||||
removing files that are no longer in the working tree.
|
||||
|
||||
-N::
|
||||
--intent-to-add::
|
||||
Record only the fact that the path will be added later. An entry
|
||||
for the path is placed in the index with no content. This is
|
||||
useful for, among other things, showing the unstaged content of
|
||||
such files with 'git diff' and committing them with 'git commit
|
||||
-a'.
|
||||
such files with `git diff` and committing them with `git commit
|
||||
-a`.
|
||||
|
||||
--refresh::
|
||||
Don't add the file(s), but only refresh their stat()
|
||||
@@ -133,7 +140,7 @@ apply.
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The optional configuration variable 'core.excludesfile' indicates a path to a
|
||||
The optional configuration variable `core.excludesfile` indicates a path to a
|
||||
file containing patterns of file names to exclude from git-add, similar to
|
||||
$GIT_DIR/info/exclude. Patterns in the exclude file are used in addition to
|
||||
those in info/exclude. See linkgit:gitrepository-layout[5].
|
||||
@@ -181,7 +188,7 @@ and type return, like this:
|
||||
What now> 1
|
||||
------------
|
||||
|
||||
You also could say "s" or "sta" or "status" above as long as the
|
||||
You also could say `s` or `sta` or `status` above as long as the
|
||||
choice is unique.
|
||||
|
||||
The main command loop has 6 subcommands (plus help and quit).
|
||||
@@ -189,9 +196,9 @@ The main command loop has 6 subcommands (plus help and quit).
|
||||
status::
|
||||
|
||||
This shows the change between HEAD and index (i.e. what will be
|
||||
committed if you say "git commit"), and between index and
|
||||
committed if you say `git commit`), and between index and
|
||||
working tree files (i.e. what you could stage further before
|
||||
"git commit" using "git-add") for each path. A sample output
|
||||
`git commit` using `git add`) for each path. A sample output
|
||||
looks like this:
|
||||
+
|
||||
------------
|
||||
|
||||
@@ -73,6 +73,7 @@ A commit comment is read from stdin. If a changelog
|
||||
entry is not provided via "<" redirection, 'git-commit-tree' will just wait
|
||||
for one to be entered and terminated with ^D.
|
||||
|
||||
include::date-formats.txt[]
|
||||
|
||||
Diagnostics
|
||||
-----------
|
||||
|
||||
@@ -11,7 +11,7 @@ SYNOPSIS
|
||||
'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]
|
||||
[(-c | -C) <commit>] [-F <file> | -m <msg>] [--reset-author]
|
||||
[--allow-empty] [--no-verify] [-e] [--author=<author>]
|
||||
[--cleanup=<mode>] [--] [[-i | -o ]<file>...]
|
||||
[--date=<date>] [--cleanup=<mode>] [--] [[-i | -o ]<file>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -74,6 +74,20 @@ OPTIONS
|
||||
authorship of the resulting commit now belongs of the committer.
|
||||
This also renews the author timestamp.
|
||||
|
||||
--short::
|
||||
When doing a dry-run, give the output in the short-format. See
|
||||
linkgit:git-status[1] for details. Implies `--dry-run`.
|
||||
|
||||
--porcelain::
|
||||
When doing a dry-run, give the output in a porcelain-ready
|
||||
format. See linkgit:git-status[1] for details. Implies
|
||||
`--dry-run`.
|
||||
|
||||
-z::
|
||||
When showing `short` or `porcelain` status output, terminate
|
||||
entries in the status output with NUL, instead of LF. If no
|
||||
format is given, implies the `--porcelain` output format.
|
||||
|
||||
-F <file>::
|
||||
--file=<file>::
|
||||
Take the commit message from the given file. Use '-' to
|
||||
@@ -85,6 +99,9 @@ OPTIONS
|
||||
an existing commit that matches the given string and its author
|
||||
name is used.
|
||||
|
||||
--date=<date>::
|
||||
Override the author date used in the commit.
|
||||
|
||||
-m <msg>::
|
||||
--message=<msg>::
|
||||
Use the given <msg> as the commit message.
|
||||
@@ -217,6 +234,8 @@ specified.
|
||||
these files are also staged for the next commit on top
|
||||
of what have been staged before.
|
||||
|
||||
:git-commit: 1
|
||||
include::date-formats.txt[]
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
@@ -37,11 +37,12 @@ existing values that match the regexp are updated or unset. If
|
||||
you want to handle the lines that do *not* match the regex, just
|
||||
prepend a single exclamation mark in front (see also <<EXAMPLES>>).
|
||||
|
||||
The type specifier can be either '--int' or '--bool', which will make
|
||||
The type specifier can be either '--int' or '--bool', to make
|
||||
'git-config' ensure that the variable(s) are of the given type and
|
||||
convert the value to the canonical form (simple decimal number for int,
|
||||
a "true" or "false" string for bool). If no type specifier is passed,
|
||||
no checks or transformations are performed on the value.
|
||||
a "true" or "false" string for bool), or '--path', which does some
|
||||
path expansion (see '--path' below). If no type specifier is passed, no
|
||||
checks or transformations are performed on the value.
|
||||
|
||||
The file-option can be one of '--system', '--global' or '--file'
|
||||
which specify where the values will be read from or written to.
|
||||
@@ -136,6 +137,13 @@ See also <<FILES>>.
|
||||
'git-config' will ensure that the output matches the format of
|
||||
either --bool or --int, as described above.
|
||||
|
||||
--path::
|
||||
'git-config' will expand leading '{tilde}' to the value of
|
||||
'$HOME', and '{tilde}user' to the home directory for the
|
||||
specified user. This option has no effect when setting the
|
||||
value (but you can use 'git config bla {tilde}/' from the
|
||||
command line to let your shell do the expansion).
|
||||
|
||||
-z::
|
||||
--null::
|
||||
For all options that output values and/or keys, always
|
||||
|
||||
@@ -277,6 +277,21 @@ In `dbdriver` and `dbuser` you can use the following variables:
|
||||
If no name can be determined, the
|
||||
numeric uid is used.
|
||||
|
||||
ENVIRONMENT
|
||||
-----------
|
||||
|
||||
These variables obviate the need for command-line options in some
|
||||
circumstances, allowing easier restricted usage through git-shell.
|
||||
|
||||
GIT_CVSSERVER_BASE_PATH takes the place of the argument to --base-path.
|
||||
|
||||
GIT_CVSSERVER_ROOT specifies a single-directory whitelist. The
|
||||
repository must still be configured to allow access through
|
||||
git-cvsserver, as described above.
|
||||
|
||||
When these environment variables are set, the corresponding
|
||||
command-line arguments may not be used.
|
||||
|
||||
Eclipse CVS Client Notes
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -311,8 +311,8 @@ change to the project.
|
||||
....
|
||||
'commit' SP <ref> LF
|
||||
mark?
|
||||
('author' SP <name> SP LT <email> GT SP <when> LF)?
|
||||
'committer' SP <name> SP LT <email> GT SP <when> LF
|
||||
('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
|
||||
'committer' (SP <name>)? SP LT <email> GT SP <when> LF
|
||||
data
|
||||
('from' SP <committish> LF)?
|
||||
('merge' SP <committish> LF)?
|
||||
@@ -657,7 +657,7 @@ lightweight (non-annotated) tags see the `reset` command below.
|
||||
....
|
||||
'tag' SP <name> LF
|
||||
'from' SP <committish> LF
|
||||
'tagger' SP <name> SP LT <email> GT SP <when> LF
|
||||
'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
|
||||
data
|
||||
....
|
||||
|
||||
|
||||
@@ -91,6 +91,10 @@ nor in any Push line of the corresponding remotes file---see below).
|
||||
will be tab-separated and sent to stdout instead of stderr. The full
|
||||
symbolic names of the refs will be given.
|
||||
|
||||
--delete::
|
||||
All listed refs are deleted from the remote repository. This is
|
||||
the same as prefixing all refs with a colon.
|
||||
|
||||
--tags::
|
||||
All refs under `$GIT_DIR/refs/tags` are pushed, in
|
||||
addition to refspecs explicitly listed on the command
|
||||
|
||||
@@ -79,6 +79,17 @@ style string if it contains an LF.
|
||||
+
|
||||
Supported if the helper has the "push" capability.
|
||||
|
||||
'import' <name>::
|
||||
Produces a fast-import stream which imports the current value
|
||||
of the named ref. It may additionally import other refs as
|
||||
needed to construct the history efficiently. The script writes
|
||||
to a helper-specific private namespace. The value of the named
|
||||
ref should be written to a location in this namespace derived
|
||||
by applying the refspecs from the "refspec" capability to the
|
||||
name of the ref.
|
||||
+
|
||||
Supported if the helper has the "import" capability.
|
||||
|
||||
If a fatal error occurs, the program writes the error message to
|
||||
stderr and exits. The caller should expect that a suitable error
|
||||
message has been printed if the child closes the connection without
|
||||
@@ -99,6 +110,19 @@ CAPABILITIES
|
||||
'push'::
|
||||
This helper supports the 'push' command.
|
||||
|
||||
'import'::
|
||||
This helper supports the 'import' command.
|
||||
|
||||
'refspec' 'spec'::
|
||||
When using the import command, expect the source ref to have
|
||||
been written to the destination ref. The earliest applicable
|
||||
refspec takes precedence. For example
|
||||
"refs/heads/*:refs/svn/origin/branches/*" means that, after an
|
||||
"import refs/heads/name", the script has written to
|
||||
refs/svn/origin/branches/name. If this capability is used at
|
||||
all, it must cover all refs reported by the list command; if
|
||||
it is not used, it is effectively "*:*"
|
||||
|
||||
REF LIST ATTRIBUTES
|
||||
-------------------
|
||||
|
||||
@@ -107,6 +131,10 @@ REF LIST ATTRIBUTES
|
||||
commands. A helper might chose to acquire the ref list by
|
||||
opening a different type of connection to the destination.
|
||||
|
||||
'unchanged'::
|
||||
This ref is unchanged since the last import or fetch, although
|
||||
the helper cannot necessarily determine what value that produced.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
'option verbosity' <N>::
|
||||
|
||||
@@ -62,6 +62,7 @@ This means that `git reset -p` is the opposite of `git add -p` (see
|
||||
linkgit:git-add[1]).
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Be quiet, only report errors.
|
||||
|
||||
<commit>::
|
||||
|
||||
@@ -12,13 +12,13 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Remove files from the index, or from the working tree and the index.
|
||||
'git-rm' will not remove a file from just your working directory.
|
||||
(There is no option to remove a file only from the work tree
|
||||
`git rm` will not remove a file from just your working directory.
|
||||
(There is no option to remove a file only from the working tree
|
||||
and yet keep it in the index; use `/bin/rm` if you want to do that.)
|
||||
The files being removed have to be identical to the tip of the branch,
|
||||
and no updates to their contents can be staged in the index,
|
||||
though that default behavior can be overridden with the `-f` option.
|
||||
When '--cached' is given, the staged content has to
|
||||
When `--cached` is given, the staged content has to
|
||||
match either the tip of the branch or the file on disk,
|
||||
allowing the file to be removed from just the index.
|
||||
|
||||
@@ -64,7 +64,7 @@ OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
'git-rm' normally outputs one line (in the form of an "rm" command)
|
||||
`git rm` normally outputs one line (in the form of an `rm` command)
|
||||
for each file removed. This option suppresses that output.
|
||||
|
||||
|
||||
@@ -81,6 +81,58 @@ two directories `d` and `d2`, there is a difference between
|
||||
using `git rm \'d\*\'` and `git rm \'d/\*\'`, as the former will
|
||||
also remove all of directory `d2`.
|
||||
|
||||
REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
|
||||
--------------------------------------------------------
|
||||
There is no option for `git rm` to remove from the index only
|
||||
the paths that have disappeared from the filesystem. However,
|
||||
depending on the use case, there are several ways that can be
|
||||
done.
|
||||
|
||||
Using "git commit -a"
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
If you intend that your next commit should record all modifications
|
||||
of tracked files in the working tree and record all removals of
|
||||
files that have been removed from the working tree with `rm`
|
||||
(as opposed to `git rm`), use `git commit -a`, as it will
|
||||
automatically notice and record all removals. You can also have a
|
||||
similar effect without committing by using `git add -u`.
|
||||
|
||||
Using "git add -A"
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
When accepting a new code drop for a vendor branch, you probably
|
||||
want to record both the removal of paths and additions of new paths
|
||||
as well as modifications of existing paths.
|
||||
|
||||
Typically you would first remove all tracked files from the working
|
||||
tree using this command:
|
||||
|
||||
----------------
|
||||
git ls-files -z | xargs -0 rm -f
|
||||
----------------
|
||||
|
||||
and then "untar" the new code in the working tree. Alternately
|
||||
you could "rsync" the changes into the working tree.
|
||||
|
||||
After that, the easiest way to record all removals, additions, and
|
||||
modifications in the working tree is:
|
||||
|
||||
----------------
|
||||
git add -A
|
||||
----------------
|
||||
|
||||
See linkgit:git-add[1].
|
||||
|
||||
Other ways
|
||||
~~~~~~~~~~
|
||||
If all you really want to do is to remove from the index the files
|
||||
that are no longer present in the working tree (perhaps because
|
||||
your working tree is dirty so that you cannot use `git commit -a`),
|
||||
use the following command:
|
||||
|
||||
----------------
|
||||
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached
|
||||
----------------
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
git rm Documentation/\\*.txt::
|
||||
|
||||
@@ -84,7 +84,7 @@ See the CONFIGURATION section for 'sendemail.multiedit'.
|
||||
--in-reply-to=<identifier>::
|
||||
Specify the contents of the first In-Reply-To header.
|
||||
Subsequent emails will refer to the previous email
|
||||
instead of this if --chain-reply-to is set (the default)
|
||||
instead of this if --chain-reply-to is set.
|
||||
Only necessary if --compose is also set. If --compose
|
||||
is not set, this will be prompted for.
|
||||
|
||||
@@ -172,8 +172,8 @@ Automating
|
||||
email sent. If disabled with "--no-chain-reply-to", all emails after
|
||||
the first will be sent as replies to the first email sent. When using
|
||||
this, it is recommended that the first file given be an overview of the
|
||||
entire patch series. Default is the value of the 'sendemail.chainreplyto'
|
||||
configuration value; if that is unspecified, default to --chain-reply-to.
|
||||
entire patch series. Disabled by default, but the 'sendemail.chainreplyto'
|
||||
configuration variable can be used to enable it.
|
||||
|
||||
--identity=<identity>::
|
||||
A configuration identity. When given, causes values in the
|
||||
|
||||
@@ -8,7 +8,7 @@ git-status - Show the working tree status
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git status' <options>...
|
||||
'git status' [<options>...] [--] [<pathspec>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -20,25 +20,90 @@ are what you _would_ commit by running `git commit`; the second and
|
||||
third are what you _could_ commit by running 'git-add' before running
|
||||
`git commit`.
|
||||
|
||||
The command takes the same set of options as 'git-commit'; it
|
||||
shows what would be committed if the same options are given to
|
||||
'git-commit'.
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
If there is no path that is different between the index file and
|
||||
the current HEAD commit (i.e., there is nothing to commit by running
|
||||
`git commit`), the command exits with non-zero status.
|
||||
-s::
|
||||
--short::
|
||||
Give the output in the short-format.
|
||||
|
||||
--porcelain::
|
||||
Give the output in a stable, easy-to-parse format for scripts.
|
||||
Currently this is identical to --short output, but is guaranteed
|
||||
not to change in the future, making it safe for scripts.
|
||||
|
||||
-u[<mode>]::
|
||||
--untracked-files[=<mode>]::
|
||||
Show untracked files (Default: 'all').
|
||||
+
|
||||
The mode parameter is optional, and is used to specify
|
||||
the handling of untracked files. The possible options are:
|
||||
+
|
||||
--
|
||||
- 'no' - Show no untracked files
|
||||
- 'normal' - Shows untracked files and directories
|
||||
- 'all' - Also shows individual files in untracked directories.
|
||||
--
|
||||
+
|
||||
See linkgit:git-config[1] for configuration variable
|
||||
used to change the default for when the option is not
|
||||
specified.
|
||||
|
||||
-z::
|
||||
Terminate entries with NUL, instead of LF. This implies
|
||||
the `--porcelain` output format if no other format is given.
|
||||
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
The output from this command is designed to be used as a commit
|
||||
template comment, and all the output lines are prefixed with '#'.
|
||||
The default, long format, is designed to be human readable,
|
||||
verbose and descriptive. They are subject to change in any time.
|
||||
|
||||
The paths mentioned in the output, unlike many other git commands, are
|
||||
made relative to the current directory if you are working in a
|
||||
subdirectory (this is on purpose, to help cutting and pasting). See
|
||||
the status.relativePaths config option below.
|
||||
|
||||
In short-format, the status of each path is shown as
|
||||
|
||||
XY PATH1 -> PATH2
|
||||
|
||||
where `PATH1` is the path in the `HEAD`, and ` -> PATH2` part is
|
||||
shown only when `PATH1` corresponds to a different path in the
|
||||
index/worktree (i.e. renamed).
|
||||
|
||||
For unmerged entries, `X` shows the status of stage #2 (i.e. ours) and `Y`
|
||||
shows the status of stage #3 (i.e. theirs).
|
||||
|
||||
For entries that do not have conflicts, `X` shows the status of the index,
|
||||
and `Y` shows the status of the work tree. For untracked paths, `XY` are
|
||||
`??`.
|
||||
|
||||
X Y Meaning
|
||||
-------------------------------------------------
|
||||
[MD] not updated
|
||||
M [ MD] updated in index
|
||||
A [ MD] added to index
|
||||
D [ MD] deleted from index
|
||||
R [ MD] renamed in index
|
||||
C [ MD] copied in index
|
||||
[MARC] index and work tree matches
|
||||
[ MARC] M work tree changed since index
|
||||
[ MARC] D deleted in work tree
|
||||
-------------------------------------------------
|
||||
D D unmerged, both deleted
|
||||
A U unmerged, added by us
|
||||
U D unmerged, deleted by them
|
||||
U A unmerged, added by them
|
||||
D U unmerged, deleted by us
|
||||
A A unmerged, both added
|
||||
U U unmerged, both modified
|
||||
-------------------------------------------------
|
||||
? ? untracked
|
||||
-------------------------------------------------
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
@@ -53,9 +118,9 @@ paths shown are relative to the repository root, not to the current
|
||||
directory.
|
||||
|
||||
If `status.submodulesummary` is set to a non zero number or true (identical
|
||||
to -1 or an unlimited number), the submodule summary will be enabled and a
|
||||
summary of commits for modified submodules will be shown (see --summary-limit
|
||||
option of linkgit:git-submodule[1]).
|
||||
to -1 or an unlimited number), the submodule summary will be enabled for
|
||||
the long format and a summary of commits for modified submodules will be
|
||||
shown (see --summary-limit option of linkgit:git-submodule[1]).
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
@@ -63,8 +128,7 @@ linkgit:gitignore[5]
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org> and
|
||||
Junio C Hamano <gitster@pobox.com>.
|
||||
Written by Junio C Hamano <gitster@pobox.com>.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.6.6
|
||||
DEF_VER=v1.6.6.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
18
INSTALL
18
INSTALL
@@ -38,13 +38,17 @@ Issues of note:
|
||||
Interactive Tools package still can install "git", but you can build it
|
||||
with --disable-transition option to avoid this.
|
||||
|
||||
- You can use git after building but without installing if you
|
||||
wanted to. Various git commands need to find other git
|
||||
commands and scripts to do their work, so you would need to
|
||||
arrange a few environment variables to tell them that their
|
||||
friends will be found in your built source area instead of at
|
||||
their standard installation area. Something like this works
|
||||
for me:
|
||||
- You can use git after building but without installing if you want
|
||||
to test drive it. Simply run git found in bin-wrappers directory
|
||||
in the build directory, or prepend that directory to your $PATH.
|
||||
This however is less efficient than running an installed git, as
|
||||
you always need an extra fork+exec to run any git subcommand.
|
||||
|
||||
It is still possible to use git without installing by setting a few
|
||||
environment variables, which was the way this was done
|
||||
traditionally. But using git found in bin-wrappers directory in
|
||||
the build directory is far simpler. As a historical reference, the
|
||||
old way went like this:
|
||||
|
||||
GIT_EXEC_PATH=`pwd`
|
||||
PATH=`pwd`:$PATH
|
||||
|
||||
105
Makefile
105
Makefile
@@ -168,6 +168,8 @@ all::
|
||||
#
|
||||
# Define NO_PERL if you do not want Perl scripts or libraries at all.
|
||||
#
|
||||
# Define NO_PYTHON if you do not want Python scripts or libraries at all.
|
||||
#
|
||||
# Define NO_TCLTK if you do not want Tcl/Tk GUI.
|
||||
#
|
||||
# The TCL_PATH variable governs the location of the Tcl interpreter
|
||||
@@ -341,6 +343,7 @@ LIB_H =
|
||||
LIB_OBJS =
|
||||
PROGRAMS =
|
||||
SCRIPT_PERL =
|
||||
SCRIPT_PYTHON =
|
||||
SCRIPT_SH =
|
||||
TEST_PROGRAMS =
|
||||
|
||||
@@ -379,6 +382,7 @@ SCRIPT_PERL += git-svn.perl
|
||||
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
|
||||
git-instaweb
|
||||
|
||||
# Empty...
|
||||
@@ -427,6 +431,15 @@ ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
|
||||
# what 'all' will build but not install in gitexecdir
|
||||
OTHER_PROGRAMS = git$X
|
||||
|
||||
# what test wrappers are needed and 'install' will install, in bindir
|
||||
BINDIR_PROGRAMS_NEED_X += git
|
||||
BINDIR_PROGRAMS_NEED_X += git-upload-pack
|
||||
BINDIR_PROGRAMS_NEED_X += git-receive-pack
|
||||
BINDIR_PROGRAMS_NEED_X += git-upload-archive
|
||||
BINDIR_PROGRAMS_NEED_X += git-shell
|
||||
|
||||
BINDIR_PROGRAMS_NO_X += git-cvsserver
|
||||
|
||||
# Set paths to tools early so that they can be used for version tests.
|
||||
ifndef SHELL_PATH
|
||||
SHELL_PATH = /bin/sh
|
||||
@@ -434,8 +447,12 @@ endif
|
||||
ifndef PERL_PATH
|
||||
PERL_PATH = /usr/bin/perl
|
||||
endif
|
||||
ifndef PYTHON_PATH
|
||||
PYTHON_PATH = /usr/bin/python
|
||||
endif
|
||||
|
||||
export PERL_PATH
|
||||
export PYTHON_PATH
|
||||
|
||||
LIB_FILE=libgit.a
|
||||
XDIFF_LIB=xdiff/lib.a
|
||||
@@ -828,6 +845,7 @@ ifeq ($(uname_O),Cygwin)
|
||||
endif
|
||||
ifeq ($(uname_S),FreeBSD)
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
OLD_ICONV = YesPlease
|
||||
NO_MEMMEM = YesPlease
|
||||
BASIC_CFLAGS += -I/usr/local/include
|
||||
BASIC_LDFLAGS += -L/usr/local/lib
|
||||
@@ -1346,6 +1364,10 @@ ifeq ($(PERL_PATH),)
|
||||
NO_PERL=NoThanks
|
||||
endif
|
||||
|
||||
ifeq ($(PYTHON_PATH),)
|
||||
NO_PYTHON=NoThanks
|
||||
endif
|
||||
|
||||
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
|
||||
QUIET_SUBDIR1 =
|
||||
|
||||
@@ -1393,6 +1415,7 @@ prefix_SQ = $(subst ','\'',$(prefix))
|
||||
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
|
||||
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
|
||||
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
|
||||
|
||||
LIBS = $(GITLIBS) $(EXTLIBS)
|
||||
@@ -1439,6 +1462,9 @@ ifndef NO_TCLTK
|
||||
endif
|
||||
ifndef NO_PERL
|
||||
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||
endif
|
||||
ifndef NO_PYTHON
|
||||
$(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||
endif
|
||||
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
|
||||
|
||||
@@ -1566,11 +1592,41 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
|
||||
mv $@+ $@
|
||||
endif # NO_PERL
|
||||
|
||||
|
||||
ifdef JSMIN
|
||||
gitweb/gitweb.min.js: gitweb/gitweb.js
|
||||
$(QUIET_GEN)$(JSMIN) <$< >$@
|
||||
endif # JSMIN
|
||||
|
||||
ifndef NO_PYTHON
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
|
||||
--no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
|
||||
instlibdir` && \
|
||||
sed -e '1{' \
|
||||
-e ' s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
|
||||
-e '}' \
|
||||
-e 's|^import sys.*|&; \\\
|
||||
import os; \\\
|
||||
sys.path[0] = os.environ.has_key("GITPYTHONLIB") and \\\
|
||||
os.environ["GITPYTHONLIB"] or \\\
|
||||
"@@INSTLIBDIR@@"|' \
|
||||
-e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
|
||||
$@.py >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
mv $@+ $@
|
||||
else # NO_PYTHON
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's|@@REASON@@|NO_PYTHON=$(NO_PYTHON)|g' \
|
||||
unimplemented.sh >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
mv $@+ $@
|
||||
endif # NO_PYTHON
|
||||
|
||||
configure: configure.ac
|
||||
$(QUIET_GEN)$(RM) $@ $<+ && \
|
||||
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
@@ -1588,7 +1644,7 @@ git.o git.spec \
|
||||
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
|
||||
%.s: %.c GIT-CFLAGS
|
||||
$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
|
||||
%.o: %.S
|
||||
%.o: %.S GIT-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
|
||||
|
||||
exec_cmd.o: exec_cmd.c GIT-CFLAGS
|
||||
@@ -1697,6 +1753,7 @@ GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
|
||||
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
|
||||
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
|
||||
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
|
||||
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
|
||||
|
||||
### Detect Tck/Tk interpreter path changes
|
||||
ifndef NO_TCLTK
|
||||
@@ -1714,19 +1771,30 @@ endif
|
||||
|
||||
### Testing rules
|
||||
|
||||
TEST_PROGRAMS += test-chmtime$X
|
||||
TEST_PROGRAMS += test-ctype$X
|
||||
TEST_PROGRAMS += test-date$X
|
||||
TEST_PROGRAMS += test-delta$X
|
||||
TEST_PROGRAMS += test-dump-cache-tree$X
|
||||
TEST_PROGRAMS += test-genrandom$X
|
||||
TEST_PROGRAMS += test-match-trees$X
|
||||
TEST_PROGRAMS += test-parse-options$X
|
||||
TEST_PROGRAMS += test-path-utils$X
|
||||
TEST_PROGRAMS += test-sha1$X
|
||||
TEST_PROGRAMS += test-sigchain$X
|
||||
TEST_PROGRAMS_NEED_X += test-chmtime
|
||||
TEST_PROGRAMS_NEED_X += test-ctype
|
||||
TEST_PROGRAMS_NEED_X += test-date
|
||||
TEST_PROGRAMS_NEED_X += test-delta
|
||||
TEST_PROGRAMS_NEED_X += test-dump-cache-tree
|
||||
TEST_PROGRAMS_NEED_X += test-genrandom
|
||||
TEST_PROGRAMS_NEED_X += test-match-trees
|
||||
TEST_PROGRAMS_NEED_X += test-parse-options
|
||||
TEST_PROGRAMS_NEED_X += test-path-utils
|
||||
TEST_PROGRAMS_NEED_X += test-sha1
|
||||
TEST_PROGRAMS_NEED_X += test-sigchain
|
||||
|
||||
all:: $(TEST_PROGRAMS)
|
||||
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
|
||||
|
||||
test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
|
||||
|
||||
all:: $(TEST_PROGRAMS) $(test_bindir_programs)
|
||||
|
||||
bin-wrappers/%: wrap-for-bin.sh
|
||||
@mkdir -p bin-wrappers
|
||||
$(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's|@@BUILD_DIR@@|$(shell pwd)|' \
|
||||
-e 's|@@PROG@@|$(@F)|' < $< > $@ && \
|
||||
chmod +x $@
|
||||
|
||||
# GNU make supports exporting all variables by "export" without parameters.
|
||||
# However, the environment gets quite big, and some programs have problems
|
||||
@@ -1787,15 +1855,20 @@ endif
|
||||
gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir))
|
||||
export gitexec_instdir
|
||||
|
||||
install_bindir_programs := $(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)) $(BINDIR_PROGRAMS_NO_X)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
|
||||
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
|
||||
$(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||
ifndef NO_PERL
|
||||
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
|
||||
endif
|
||||
ifndef NO_PYTHON
|
||||
$(MAKE) -C git_remote_helpers prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
|
||||
endif
|
||||
ifndef NO_TCLTK
|
||||
$(MAKE) -C gitk-git install
|
||||
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
|
||||
@@ -1902,6 +1975,7 @@ clean:
|
||||
$(LIB_FILE) $(XDIFF_LIB)
|
||||
$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||
$(RM) $(TEST_PROGRAMS)
|
||||
$(RM) -r bin-wrappers
|
||||
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
|
||||
$(RM) -r autom4te.cache
|
||||
$(RM) config.log config.mak.autogen config.mak.append config.status config.cache
|
||||
@@ -1912,6 +1986,9 @@ clean:
|
||||
ifndef NO_PERL
|
||||
$(RM) gitweb/gitweb.cgi
|
||||
$(MAKE) -C perl clean
|
||||
endif
|
||||
ifndef NO_PYTHON
|
||||
$(MAKE) -C git_remote_helpers clean
|
||||
endif
|
||||
$(MAKE) -C templates/ clean
|
||||
$(MAKE) -C t/ clean
|
||||
|
||||
14
base85.c
14
base85.c
@@ -57,14 +57,8 @@ int decode_85(char *dst, const char *buffer, int len)
|
||||
de = de85[ch];
|
||||
if (--de < 0)
|
||||
return error("invalid base85 alphabet %c", ch);
|
||||
/*
|
||||
* Detect overflow. The largest
|
||||
* 5-letter possible is "|NsC0" to
|
||||
* encode 0xffffffff, and "|NsC" gives
|
||||
* 0x03030303 at this point (i.e.
|
||||
* 0xffffffff = 0x03030303 * 85).
|
||||
*/
|
||||
if (0x03030303 < acc ||
|
||||
/* Detect overflow. */
|
||||
if (0xffffffff / 85 < acc ||
|
||||
0xffffffff - de < (acc *= 85))
|
||||
return error("invalid base85 sequence %.5s", buffer-5);
|
||||
acc += de;
|
||||
@@ -84,8 +78,6 @@ int decode_85(char *dst, const char *buffer, int len)
|
||||
|
||||
void encode_85(char *buf, const unsigned char *data, int bytes)
|
||||
{
|
||||
prep_base85();
|
||||
|
||||
say("encode 85");
|
||||
while (bytes) {
|
||||
unsigned acc = 0;
|
||||
@@ -118,7 +110,7 @@ int main(int ac, char **av)
|
||||
int len = strlen(av[2]);
|
||||
encode_85(buf, av[2], len);
|
||||
if (len <= 26) len = len + 'A' - 1;
|
||||
else len = len + 'a' - 26 + 1;
|
||||
else len = len + 'a' - 26 - 1;
|
||||
printf("encoded: %c%s\n", len, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
4
bisect.c
4
bisect.c
@@ -813,11 +813,11 @@ static void handle_skipped_merge_base(const unsigned char *mb)
|
||||
char *bad_hex = sha1_to_hex(current_bad_sha1);
|
||||
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
|
||||
|
||||
fprintf(stderr, "Warning: the merge base between %s and [%s] "
|
||||
warning("the merge base between %s and [%s] "
|
||||
"must be skipped.\n"
|
||||
"So we cannot be sure the first bad commit is "
|
||||
"between %s and %s.\n"
|
||||
"We continue anyway.\n",
|
||||
"We continue anyway.",
|
||||
bad_hex, good_hex, mb_hex, bad_hex);
|
||||
free(good_hex);
|
||||
}
|
||||
|
||||
@@ -638,10 +638,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
rename_branch(head, argv[0], rename > 1);
|
||||
else if (rename && (argc == 2))
|
||||
rename_branch(argv[0], argv[1], rename > 1);
|
||||
else if (argc <= 2)
|
||||
else if (argc <= 2) {
|
||||
if (kinds != REF_LOCAL_BRANCH)
|
||||
die("-a and -r options to 'git branch' do not make sense with a branch name");
|
||||
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
|
||||
force_create, reflog, track);
|
||||
else
|
||||
} else
|
||||
usage_with_options(builtin_branch_usage, options);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -397,7 +397,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
topts.initial_checkout = is_cache_unborn();
|
||||
topts.update = 1;
|
||||
topts.merge = 1;
|
||||
topts.gently = opts->merge;
|
||||
topts.gently = opts->merge && old->commit;
|
||||
topts.verbose_update = !opts->quiet;
|
||||
topts.fn = twoway_merge;
|
||||
topts.dir = xcalloc(1, sizeof(*topts.dir));
|
||||
@@ -422,7 +422,13 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
struct merge_options o;
|
||||
if (!opts->merge)
|
||||
return 1;
|
||||
parse_commit(old->commit);
|
||||
|
||||
/*
|
||||
* Without old->commit, the below is the same as
|
||||
* the two-tree unpack we already tried and failed.
|
||||
*/
|
||||
if (!old->commit)
|
||||
return 1;
|
||||
|
||||
/* Do more real merge */
|
||||
|
||||
|
||||
@@ -362,9 +362,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
const char *repo_name, *repo, *work_tree, *git_dir;
|
||||
char *path, *dir;
|
||||
int dest_exists;
|
||||
const struct ref *refs, *remote_head, *mapped_refs;
|
||||
const struct ref *refs, *remote_head;
|
||||
const struct ref *remote_head_points_at;
|
||||
const struct ref *our_head_points_at;
|
||||
struct ref *mapped_refs;
|
||||
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
|
||||
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
|
||||
struct transport *transport = NULL;
|
||||
|
||||
136
builtin-commit.c
136
builtin-commit.c
@@ -24,6 +24,7 @@
|
||||
#include "string-list.h"
|
||||
#include "rerere.h"
|
||||
#include "unpack-trees.h"
|
||||
#include "quote.h"
|
||||
|
||||
static const char * const builtin_commit_usage[] = {
|
||||
"git commit [options] [--] <filepattern>...",
|
||||
@@ -35,7 +36,7 @@ static const char * const builtin_status_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static unsigned char head_sha1[20], merge_head_sha1[20];
|
||||
static unsigned char head_sha1[20];
|
||||
static char *use_message_buffer;
|
||||
static const char commit_editmsg[] = "COMMIT_EDITMSG";
|
||||
static struct lock_file index_lock; /* real index */
|
||||
@@ -52,7 +53,7 @@ static char *edit_message, *use_message;
|
||||
static char *author_name, *author_email, *author_date;
|
||||
static int all, edit_flag, also, interactive, only, amend, signoff;
|
||||
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
||||
static char *untracked_files_arg;
|
||||
static char *untracked_files_arg, *force_date;
|
||||
/*
|
||||
* The default commit message cleanup mode will remove the lines
|
||||
* beginning with # (shell comments) and leading and trailing
|
||||
@@ -71,6 +72,13 @@ static int use_editor = 1, initial_commit, in_merge;
|
||||
static const char *only_include_assumed;
|
||||
static struct strbuf message;
|
||||
|
||||
static int null_termination;
|
||||
static enum {
|
||||
STATUS_FORMAT_LONG,
|
||||
STATUS_FORMAT_SHORT,
|
||||
STATUS_FORMAT_PORCELAIN,
|
||||
} status_format = STATUS_FORMAT_LONG;
|
||||
|
||||
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct strbuf *buf = opt->value;
|
||||
@@ -86,10 +94,11 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
|
||||
static struct option builtin_commit_options[] = {
|
||||
OPT__QUIET(&quiet),
|
||||
OPT__VERBOSE(&verbose),
|
||||
OPT_GROUP("Commit message options"),
|
||||
|
||||
OPT_GROUP("Commit message options"),
|
||||
OPT_FILENAME('F', "file", &logfile, "read log from file"),
|
||||
OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
|
||||
OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"),
|
||||
OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
|
||||
OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"),
|
||||
OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
|
||||
@@ -97,6 +106,8 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
|
||||
OPT_FILENAME('t', "template", &template_file, "use specified template file"),
|
||||
OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
|
||||
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
|
||||
/* end commit message options */
|
||||
|
||||
OPT_GROUP("Commit contents options"),
|
||||
OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
|
||||
@@ -105,10 +116,16 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
|
||||
OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
|
||||
OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
|
||||
OPT_SET_INT(0, "short", &status_format, "show status concisely",
|
||||
STATUS_FORMAT_SHORT),
|
||||
OPT_SET_INT(0, "porcelain", &status_format,
|
||||
"show porcelain output format", STATUS_FORMAT_PORCELAIN),
|
||||
OPT_BOOLEAN('z', "null", &null_termination,
|
||||
"terminate entries with NUL"),
|
||||
OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
|
||||
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
|
||||
OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
|
||||
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
|
||||
/* end commit contents options */
|
||||
|
||||
OPT_END()
|
||||
};
|
||||
@@ -306,7 +323,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
|
||||
*/
|
||||
commit_style = COMMIT_PARTIAL;
|
||||
|
||||
if (file_exists(git_path("MERGE_HEAD")))
|
||||
if (in_merge)
|
||||
die("cannot do a partial commit during a merge.");
|
||||
|
||||
memset(&partial, 0, sizeof(partial));
|
||||
@@ -347,6 +364,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
|
||||
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
|
||||
struct wt_status *s)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (s->relative_paths)
|
||||
s->prefix = prefix;
|
||||
|
||||
@@ -358,8 +377,21 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
|
||||
s->index_file = index_file;
|
||||
s->fp = fp;
|
||||
s->nowarn = nowarn;
|
||||
s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
|
||||
|
||||
wt_status_print(s);
|
||||
wt_status_collect(s);
|
||||
|
||||
switch (status_format) {
|
||||
case STATUS_FORMAT_SHORT:
|
||||
wt_shortstatus_print(s, null_termination);
|
||||
break;
|
||||
case STATUS_FORMAT_PORCELAIN:
|
||||
wt_porcelain_print(s, null_termination);
|
||||
break;
|
||||
case STATUS_FORMAT_LONG:
|
||||
wt_status_print(s);
|
||||
break;
|
||||
}
|
||||
|
||||
return s->commitable;
|
||||
}
|
||||
@@ -410,6 +442,9 @@ static void determine_author_info(void)
|
||||
email = xstrndup(lb + 2, rb - (lb + 2));
|
||||
}
|
||||
|
||||
if (force_date)
|
||||
date = force_date;
|
||||
|
||||
author_name = name;
|
||||
author_email = email;
|
||||
author_date = date;
|
||||
@@ -735,6 +770,21 @@ static const char *find_author_by_nickname(const char *name)
|
||||
die("No existing author found with '%s'", name);
|
||||
}
|
||||
|
||||
|
||||
static void handle_untracked_files_arg(struct wt_status *s)
|
||||
{
|
||||
if (!untracked_files_arg)
|
||||
; /* default already initialized */
|
||||
else if (!strcmp(untracked_files_arg, "no"))
|
||||
s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
|
||||
else if (!strcmp(untracked_files_arg, "normal"))
|
||||
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
else if (!strcmp(untracked_files_arg, "all"))
|
||||
s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
|
||||
else
|
||||
die("Invalid untracked files mode '%s'", untracked_files_arg);
|
||||
}
|
||||
|
||||
static int parse_and_validate_options(int argc, const char *argv[],
|
||||
const char * const usage[],
|
||||
const char *prefix,
|
||||
@@ -761,9 +811,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
if (get_sha1("HEAD", head_sha1))
|
||||
initial_commit = 1;
|
||||
|
||||
if (!get_sha1("MERGE_HEAD", merge_head_sha1))
|
||||
in_merge = 1;
|
||||
|
||||
/* Sanity check options */
|
||||
if (amend && initial_commit)
|
||||
die("You have nothing to amend.");
|
||||
@@ -843,22 +890,18 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
else
|
||||
die("Invalid cleanup mode %s", cleanup_arg);
|
||||
|
||||
if (!untracked_files_arg)
|
||||
; /* default already initialized */
|
||||
else if (!strcmp(untracked_files_arg, "no"))
|
||||
s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
|
||||
else if (!strcmp(untracked_files_arg, "normal"))
|
||||
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
else if (!strcmp(untracked_files_arg, "all"))
|
||||
s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
|
||||
else
|
||||
die("Invalid untracked files mode '%s'", untracked_files_arg);
|
||||
handle_untracked_files_arg(s);
|
||||
|
||||
if (all && argc > 0)
|
||||
die("Paths with -a does not make sense.");
|
||||
else if (interactive && argc > 0)
|
||||
die("Paths with --interactive does not make sense.");
|
||||
|
||||
if (null_termination && status_format == STATUS_FORMAT_LONG)
|
||||
status_format = STATUS_FORMAT_PORCELAIN;
|
||||
if (status_format != STATUS_FORMAT_LONG)
|
||||
dry_run = 1;
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
@@ -940,17 +983,63 @@ static int git_status_config(const char *k, const char *v, void *cb)
|
||||
int cmd_status(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct wt_status s;
|
||||
unsigned char sha1[20];
|
||||
static struct option builtin_status_options[] = {
|
||||
OPT__VERBOSE(&verbose),
|
||||
OPT_SET_INT('s', "short", &status_format,
|
||||
"show status concisely", STATUS_FORMAT_SHORT),
|
||||
OPT_SET_INT(0, "porcelain", &status_format,
|
||||
"show porcelain output format",
|
||||
STATUS_FORMAT_PORCELAIN),
|
||||
OPT_BOOLEAN('z', "null", &null_termination,
|
||||
"terminate entries with NUL"),
|
||||
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
|
||||
"mode",
|
||||
"show untracked files, optional modes: all, normal, no. (Default: all)",
|
||||
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
if (null_termination && status_format == STATUS_FORMAT_LONG)
|
||||
status_format = STATUS_FORMAT_PORCELAIN;
|
||||
|
||||
wt_status_prepare(&s);
|
||||
git_config(git_status_config, &s);
|
||||
in_merge = file_exists(git_path("MERGE_HEAD"));
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_status_options,
|
||||
builtin_status_usage, 0);
|
||||
handle_untracked_files_arg(&s);
|
||||
|
||||
if (*argv)
|
||||
s.pathspec = get_pathspec(prefix, argv);
|
||||
|
||||
read_cache();
|
||||
refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
|
||||
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
|
||||
s.in_merge = in_merge;
|
||||
wt_status_collect(&s);
|
||||
|
||||
if (s.relative_paths)
|
||||
s.prefix = prefix;
|
||||
if (s.use_color == -1)
|
||||
s.use_color = git_use_color_default;
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_status_usage,
|
||||
prefix, &s);
|
||||
return dry_run_commit(argc, argv, prefix, &s);
|
||||
switch (status_format) {
|
||||
case STATUS_FORMAT_SHORT:
|
||||
wt_shortstatus_print(&s, null_termination);
|
||||
break;
|
||||
case STATUS_FORMAT_PORCELAIN:
|
||||
wt_porcelain_print(&s, null_termination);
|
||||
break;
|
||||
case STATUS_FORMAT_LONG:
|
||||
s.verbose = verbose;
|
||||
wt_status_print(&s);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
@@ -1026,10 +1115,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
|
||||
wt_status_prepare(&s);
|
||||
git_config(git_commit_config, &s);
|
||||
in_merge = file_exists(git_path("MERGE_HEAD"));
|
||||
s.in_merge = in_merge;
|
||||
|
||||
if (s.use_color == -1)
|
||||
s.use_color = git_use_color_default;
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
|
||||
prefix, &s);
|
||||
if (dry_run) {
|
||||
|
||||
@@ -45,6 +45,7 @@ static int end_null;
|
||||
#define TYPE_BOOL (1<<0)
|
||||
#define TYPE_INT (1<<1)
|
||||
#define TYPE_BOOL_OR_INT (1<<2)
|
||||
#define TYPE_PATH (1<<3)
|
||||
|
||||
static struct option builtin_config_options[] = {
|
||||
OPT_GROUP("Config file location"),
|
||||
@@ -69,6 +70,7 @@ static struct option builtin_config_options[] = {
|
||||
OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
|
||||
OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
|
||||
OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
|
||||
OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
|
||||
OPT_GROUP("Other"),
|
||||
OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
|
||||
OPT_END(),
|
||||
@@ -94,6 +96,7 @@ static int show_config(const char *key_, const char *value_, void *cb)
|
||||
{
|
||||
char value[256];
|
||||
const char *vptr = value;
|
||||
int must_free_vptr = 0;
|
||||
int dup_error = 0;
|
||||
|
||||
if (!use_key_regexp && strcmp(key_, key))
|
||||
@@ -123,6 +126,9 @@ static int show_config(const char *key_, const char *value_, void *cb)
|
||||
vptr = v ? "true" : "false";
|
||||
else
|
||||
sprintf(value, "%d", v);
|
||||
} else if (types == TYPE_PATH) {
|
||||
git_config_pathname(&vptr, key_, value_);
|
||||
must_free_vptr = 1;
|
||||
}
|
||||
else
|
||||
vptr = value_?value_:"";
|
||||
@@ -133,6 +139,12 @@ static int show_config(const char *key_, const char *value_, void *cb)
|
||||
}
|
||||
else
|
||||
printf("%s%c", vptr, term);
|
||||
if (must_free_vptr)
|
||||
/* If vptr must be freed, it's a pointer to a
|
||||
* dynamically allocated buffer, it's safe to cast to
|
||||
* const.
|
||||
*/
|
||||
free((char *)vptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -215,7 +227,13 @@ static char *normalize_value(const char *key, const char *value)
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
if (types == 0)
|
||||
if (types == 0 || types == TYPE_PATH)
|
||||
/*
|
||||
* We don't do normalization for TYPE_PATH here: If
|
||||
* the path is like ~/foobar/, we prefer to store
|
||||
* "~/foobar/" in the config file, and to expand the ~
|
||||
* when retrieving the value.
|
||||
*/
|
||||
normalized = xstrdup(value);
|
||||
else {
|
||||
normalized = xmalloc(64);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
static void count_objects(DIR *d, char *path, int len, int verbose,
|
||||
unsigned long *loose,
|
||||
unsigned long *loose_size,
|
||||
off_t *loose_size,
|
||||
unsigned long *packed_loose,
|
||||
unsigned long *garbage)
|
||||
{
|
||||
@@ -77,7 +77,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
|
||||
int len = strlen(objdir);
|
||||
char *path = xmalloc(len + 50);
|
||||
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
|
||||
unsigned long loose_size = 0;
|
||||
off_t loose_size = 0;
|
||||
struct option opts[] = {
|
||||
OPT__VERBOSE(&verbose),
|
||||
OPT_END(),
|
||||
@@ -103,7 +103,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
|
||||
if (verbose) {
|
||||
struct packed_git *p;
|
||||
unsigned long num_pack = 0;
|
||||
unsigned long size_pack = 0;
|
||||
off_t size_pack = 0;
|
||||
if (!packed_git)
|
||||
prepare_packed_git();
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
@@ -116,15 +116,15 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
|
||||
num_pack++;
|
||||
}
|
||||
printf("count: %lu\n", loose);
|
||||
printf("size: %lu\n", loose_size / 1024);
|
||||
printf("size: %lu\n", (unsigned long) (loose_size / 1024));
|
||||
printf("in-pack: %lu\n", packed);
|
||||
printf("packs: %lu\n", num_pack);
|
||||
printf("size-pack: %lu\n", size_pack / 1024);
|
||||
printf("size-pack: %lu\n", (unsigned long) (size_pack / 1024));
|
||||
printf("prune-packable: %lu\n", packed_loose);
|
||||
printf("garbage: %lu\n", garbage);
|
||||
}
|
||||
else
|
||||
printf("%lu objects, %lu kilobytes\n",
|
||||
loose, loose_size / 1024);
|
||||
loose, (unsigned long) (loose_size / 1024));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -322,7 +322,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
if (!fp)
|
||||
return error("cannot open %s: %s\n", filename, strerror(errno));
|
||||
|
||||
url = transport_anonymize_url(raw_url);
|
||||
if (raw_url)
|
||||
url = transport_anonymize_url(raw_url);
|
||||
else
|
||||
url = xstrdup("foreign");
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
struct ref *ref = NULL;
|
||||
|
||||
@@ -819,7 +822,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
|
||||
if (!remote)
|
||||
die("Where do you want to fetch from today?");
|
||||
|
||||
transport = transport_get(remote, remote->url[0]);
|
||||
transport = transport_get(remote, NULL);
|
||||
if (verbosity >= 2)
|
||||
transport->verbose = verbosity <= 3 ? verbosity : 3;
|
||||
if (verbosity < 0)
|
||||
|
||||
@@ -180,12 +180,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||
char buf[80];
|
||||
|
||||
struct option builtin_gc_options[] = {
|
||||
OPT__QUIET(&quiet),
|
||||
{ OPTION_STRING, 0, "prune", &prune_expire, "date",
|
||||
"prune unreferenced objects",
|
||||
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
|
||||
OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
|
||||
OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
|
||||
OPT_BOOLEAN('q', "quiet", &quiet, "suppress progress reports"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
||||
@@ -23,13 +23,14 @@ static struct man_viewer_info_list {
|
||||
} *man_viewer_info_list;
|
||||
|
||||
enum help_format {
|
||||
HELP_FORMAT_NONE,
|
||||
HELP_FORMAT_MAN,
|
||||
HELP_FORMAT_INFO,
|
||||
HELP_FORMAT_WEB,
|
||||
};
|
||||
|
||||
static int show_all = 0;
|
||||
static enum help_format help_format = HELP_FORMAT_MAN;
|
||||
static enum help_format help_format = HELP_FORMAT_NONE;
|
||||
static struct option builtin_help_options[] = {
|
||||
OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
|
||||
OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
|
||||
@@ -415,10 +416,12 @@ int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int nongit;
|
||||
const char *alias;
|
||||
enum help_format parsed_help_format;
|
||||
load_command_list("git-", &main_cmds, &other_cmds);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, builtin_help_options,
|
||||
builtin_help_usage, 0);
|
||||
parsed_help_format = help_format;
|
||||
|
||||
if (show_all) {
|
||||
printf("usage: %s\n\n", git_usage_string);
|
||||
@@ -437,6 +440,9 @@ int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
setup_git_directory_gently(&nongit);
|
||||
git_config(git_help_config, NULL);
|
||||
|
||||
if (parsed_help_format != HELP_FORMAT_NONE)
|
||||
help_format = parsed_help_format;
|
||||
|
||||
alias = alias_lookup(argv[0]);
|
||||
if (alias && !is_git_command(argv[0])) {
|
||||
printf("`git %s' is aliased to `%s'\n", argv[0], alias);
|
||||
@@ -444,6 +450,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
switch (help_format) {
|
||||
case HELP_FORMAT_NONE:
|
||||
case HELP_FORMAT_MAN:
|
||||
show_man_page(argv[0]);
|
||||
break;
|
||||
|
||||
@@ -567,7 +567,7 @@ static int reopen_stdout(struct commit *commit, struct rev_info *rev)
|
||||
|
||||
get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
|
||||
|
||||
if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
|
||||
if (!DIFF_OPT_TST(&rev->diffopt, QUICK))
|
||||
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
|
||||
|
||||
if (freopen(filename.buf, "w", stdout) == NULL)
|
||||
|
||||
@@ -89,7 +89,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
||||
remote = remote_get(dest);
|
||||
if (!remote->url_nr)
|
||||
die("remote %s has no configured URL", dest);
|
||||
transport = transport_get(remote, remote->url[0]);
|
||||
transport = transport_get(remote, NULL);
|
||||
if (uploadpack != NULL)
|
||||
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
|
||||
|
||||
|
||||
@@ -169,9 +169,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
* check both source and destination
|
||||
*/
|
||||
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
|
||||
fprintf(stderr, "Warning: %s;"
|
||||
" will overwrite!\n",
|
||||
bad);
|
||||
warning("%s; will overwrite!", bad);
|
||||
bad = NULL;
|
||||
} else
|
||||
bad = "Cannot overwrite";
|
||||
|
||||
@@ -15,6 +15,7 @@ static const char * const push_usage[] = {
|
||||
};
|
||||
|
||||
static int thin;
|
||||
static int deleterefs;
|
||||
static const char *receivepack;
|
||||
|
||||
static const char **refspec;
|
||||
@@ -39,11 +40,24 @@ static void set_refspecs(const char **refs, int nr)
|
||||
if (nr <= ++i)
|
||||
die("tag shorthand without <tag>");
|
||||
len = strlen(refs[i]) + 11;
|
||||
tag = xmalloc(len);
|
||||
strcpy(tag, "refs/tags/");
|
||||
if (deleterefs) {
|
||||
tag = xmalloc(len+1);
|
||||
strcpy(tag, ":refs/tags/");
|
||||
} else {
|
||||
tag = xmalloc(len);
|
||||
strcpy(tag, "refs/tags/");
|
||||
}
|
||||
strcat(tag, refs[i]);
|
||||
ref = tag;
|
||||
}
|
||||
} else if (deleterefs && !strchr(ref, ':')) {
|
||||
char *delref;
|
||||
int len = strlen(ref)+1;
|
||||
delref = xmalloc(len);
|
||||
strcpy(delref, ":");
|
||||
strcat(delref, ref);
|
||||
ref = delref;
|
||||
} else if (deleterefs)
|
||||
die("--delete only accepts plain target ref names");
|
||||
add_refspec(ref);
|
||||
}
|
||||
}
|
||||
@@ -87,6 +101,37 @@ static void setup_default_push_refspecs(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int push_with_options(struct transport *transport, int flags)
|
||||
{
|
||||
int err;
|
||||
int nonfastforward;
|
||||
if (receivepack)
|
||||
transport_set_option(transport,
|
||||
TRANS_OPT_RECEIVEPACK, receivepack);
|
||||
if (thin)
|
||||
transport_set_option(transport, TRANS_OPT_THIN, "yes");
|
||||
|
||||
if (flags & TRANSPORT_PUSH_VERBOSE)
|
||||
fprintf(stderr, "Pushing to %s\n", transport->url);
|
||||
err = transport_push(transport, refspec_nr, refspec, flags,
|
||||
&nonfastforward);
|
||||
if (err != 0)
|
||||
error("failed to push some refs to '%s'", transport->url);
|
||||
|
||||
err |= transport_disconnect(transport);
|
||||
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
if (nonfastforward && advice_push_nonfastforward) {
|
||||
printf("To prevent you from losing history, non-fast-forward updates were rejected\n"
|
||||
"Merge the remote changes before pushing again. See the 'non-fast-forward'\n"
|
||||
"section of 'git push --help' for details.\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int do_push(const char *repo, int flags)
|
||||
{
|
||||
int i, errs;
|
||||
@@ -135,33 +180,19 @@ static int do_push(const char *repo, int flags)
|
||||
url = remote->url;
|
||||
url_nr = remote->url_nr;
|
||||
}
|
||||
for (i = 0; i < url_nr; i++) {
|
||||
struct transport *transport =
|
||||
transport_get(remote, url[i]);
|
||||
int err;
|
||||
int nonfastforward;
|
||||
if (receivepack)
|
||||
transport_set_option(transport,
|
||||
TRANS_OPT_RECEIVEPACK, receivepack);
|
||||
if (thin)
|
||||
transport_set_option(transport, TRANS_OPT_THIN, "yes");
|
||||
|
||||
if (flags & TRANSPORT_PUSH_VERBOSE)
|
||||
fprintf(stderr, "Pushing to %s\n", url[i]);
|
||||
err = transport_push(transport, refspec_nr, refspec, flags,
|
||||
&nonfastforward);
|
||||
err |= transport_disconnect(transport);
|
||||
|
||||
if (!err)
|
||||
continue;
|
||||
|
||||
error("failed to push some refs to '%s'", url[i]);
|
||||
if (nonfastforward && advice_push_nonfastforward) {
|
||||
printf("To prevent you from losing history, non-fast-forward updates were rejected\n"
|
||||
"Merge the remote changes before pushing again. See the 'non-fast-forward'\n"
|
||||
"section of 'git push --help' for details.\n");
|
||||
if (url_nr) {
|
||||
for (i = 0; i < url_nr; i++) {
|
||||
struct transport *transport =
|
||||
transport_get(remote, url[i]);
|
||||
if (push_with_options(transport, flags))
|
||||
errs++;
|
||||
}
|
||||
errs++;
|
||||
} else {
|
||||
struct transport *transport =
|
||||
transport_get(remote, NULL);
|
||||
|
||||
if (push_with_options(transport, flags))
|
||||
errs++;
|
||||
}
|
||||
return !!errs;
|
||||
}
|
||||
@@ -179,6 +210,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
|
||||
OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
|
||||
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
|
||||
OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
|
||||
OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
|
||||
OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
|
||||
OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
|
||||
@@ -192,6 +224,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
git_config(git_default_config, NULL);
|
||||
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
|
||||
|
||||
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
|
||||
die("--delete is incompatible with --all, --mirror and --tags");
|
||||
if (deleterefs && argc < 2)
|
||||
die("--delete doesn't make sense without any refs");
|
||||
|
||||
if (tags)
|
||||
add_refspec("refs/tags/*");
|
||||
|
||||
|
||||
@@ -204,59 +204,47 @@ static int is_ref_checked_out(const char *ref)
|
||||
return !strcmp(head_name, ref);
|
||||
}
|
||||
|
||||
static char *warn_unconfigured_deny_msg[] = {
|
||||
"Updating the currently checked out branch may cause confusion,",
|
||||
"as the index and work tree do not reflect changes that are in HEAD.",
|
||||
"As a result, you may see the changes you just pushed into it",
|
||||
"reverted when you run 'git diff' over there, and you may want",
|
||||
"to run 'git reset --hard' before starting to work to recover.",
|
||||
static char *refuse_unconfigured_deny_msg[] = {
|
||||
"By default, updating the current branch in a non-bare repository",
|
||||
"is denied, because it will make the index and work tree inconsistent",
|
||||
"with what you pushed, and will require 'git reset --hard' to match",
|
||||
"the work tree to HEAD.",
|
||||
"",
|
||||
"You can set 'receive.denyCurrentBranch' configuration variable to",
|
||||
"'refuse' in the remote repository to forbid pushing into its",
|
||||
"current branch."
|
||||
"'ignore' or 'warn' in the remote repository to allow pushing into",
|
||||
"its current branch; however, this is not recommended unless you",
|
||||
"arranged to update its work tree to match what you pushed in some",
|
||||
"other way.",
|
||||
"",
|
||||
"To allow pushing into the current branch, you can set it to 'ignore';",
|
||||
"but this is not recommended unless you arranged to update its work",
|
||||
"tree to match what you pushed in some other way.",
|
||||
"",
|
||||
"To squelch this message, you can set it to 'warn'.",
|
||||
"",
|
||||
"Note that the default will change in a future version of git",
|
||||
"to refuse updating the current branch unless you have the",
|
||||
"configuration variable set to either 'ignore' or 'warn'."
|
||||
"To squelch this message and still keep the default behaviour, set",
|
||||
"'receive.denyCurrentBranch' configuration variable to 'refuse'."
|
||||
};
|
||||
|
||||
static void warn_unconfigured_deny(void)
|
||||
static void refuse_unconfigured_deny(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(warn_unconfigured_deny_msg); i++)
|
||||
warning("%s", warn_unconfigured_deny_msg[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
|
||||
error("%s", refuse_unconfigured_deny_msg[i]);
|
||||
}
|
||||
|
||||
static char *warn_unconfigured_deny_delete_current_msg[] = {
|
||||
"Deleting the current branch can cause confusion by making the next",
|
||||
"'git clone' not check out any file.",
|
||||
static char *refuse_unconfigured_deny_delete_current_msg[] = {
|
||||
"By default, deleting the current branch is denied, because the next",
|
||||
"'git clone' won't result in any file checked out, causing confusion.",
|
||||
"",
|
||||
"You can set 'receive.denyDeleteCurrent' configuration variable to",
|
||||
"'refuse' in the remote repository to disallow deleting the current",
|
||||
"branch.",
|
||||
"'warn' or 'ignore' in the remote repository to allow deleting the",
|
||||
"current branch, with or without a warning message.",
|
||||
"",
|
||||
"You can set it to 'ignore' to allow such a delete without a warning.",
|
||||
"",
|
||||
"To make this warning message less loud, you can set it to 'warn'.",
|
||||
"",
|
||||
"Note that the default will change in a future version of git",
|
||||
"to refuse deleting the current branch unless you have the",
|
||||
"configuration variable set to either 'ignore' or 'warn'."
|
||||
"To squelch this message, you can set it to 'refuse'."
|
||||
};
|
||||
|
||||
static void warn_unconfigured_deny_delete_current(void)
|
||||
static void refuse_unconfigured_deny_delete_current(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0;
|
||||
i < ARRAY_SIZE(warn_unconfigured_deny_delete_current_msg);
|
||||
i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
|
||||
i++)
|
||||
warning("%s", warn_unconfigured_deny_delete_current_msg[i]);
|
||||
error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
|
||||
}
|
||||
|
||||
static const char *update(struct command *cmd)
|
||||
@@ -276,14 +264,14 @@ static const char *update(struct command *cmd)
|
||||
switch (deny_current_branch) {
|
||||
case DENY_IGNORE:
|
||||
break;
|
||||
case DENY_UNCONFIGURED:
|
||||
case DENY_WARN:
|
||||
warning("updating the current branch");
|
||||
if (deny_current_branch == DENY_UNCONFIGURED)
|
||||
warn_unconfigured_deny();
|
||||
break;
|
||||
case DENY_REFUSE:
|
||||
case DENY_UNCONFIGURED:
|
||||
error("refusing to update checked out branch: %s", name);
|
||||
if (deny_current_branch == DENY_UNCONFIGURED)
|
||||
refuse_unconfigured_deny();
|
||||
return "branch is currently checked out";
|
||||
}
|
||||
}
|
||||
@@ -305,12 +293,12 @@ static const char *update(struct command *cmd)
|
||||
case DENY_IGNORE:
|
||||
break;
|
||||
case DENY_WARN:
|
||||
case DENY_UNCONFIGURED:
|
||||
if (deny_delete_current == DENY_UNCONFIGURED)
|
||||
warn_unconfigured_deny_delete_current();
|
||||
warning("deleting the current branch");
|
||||
break;
|
||||
case DENY_REFUSE:
|
||||
case DENY_UNCONFIGURED:
|
||||
if (deny_delete_current == DENY_UNCONFIGURED)
|
||||
refuse_unconfigured_deny_delete_current();
|
||||
error("refusing to delete the current branch: %s", name);
|
||||
return "deletion of the current branch prohibited";
|
||||
}
|
||||
|
||||
@@ -1238,13 +1238,11 @@ static int update(int argc, const char **argv)
|
||||
fetch_argv[fetch_argc++] = "--prune";
|
||||
if (verbose)
|
||||
fetch_argv[fetch_argc++] = "-v";
|
||||
if (argc < 2) {
|
||||
fetch_argv[fetch_argc++] = "--multiple";
|
||||
if (argc < 2)
|
||||
fetch_argv[fetch_argc++] = "default";
|
||||
} else {
|
||||
fetch_argv[fetch_argc++] = "--multiple";
|
||||
for (i = 1; i < argc; i++)
|
||||
fetch_argv[fetch_argc++] = argv[i];
|
||||
}
|
||||
for (i = 1; i < argc; i++)
|
||||
fetch_argv[fetch_argc++] = argv[i];
|
||||
|
||||
if (strcmp(fetch_argv[fetch_argc-1], "default") == 0) {
|
||||
git_config(get_remote_default, &default_defined);
|
||||
|
||||
@@ -202,6 +202,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
struct commit *commit;
|
||||
char *reflog_action, msg[1024];
|
||||
const struct option options[] = {
|
||||
OPT__QUIET(&quiet),
|
||||
OPT_SET_INT(0, "mixed", &reset_type,
|
||||
"reset HEAD and index", MIXED),
|
||||
OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
|
||||
@@ -209,8 +210,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
"reset HEAD, index and working tree", HARD),
|
||||
OPT_SET_INT(0, "merge", &reset_type,
|
||||
"reset HEAD, index and working tree", MERGE),
|
||||
OPT_BOOLEAN('q', NULL, &quiet,
|
||||
"disable showing new HEAD in hard reset and progress message"),
|
||||
OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
|
||||
OPT_END()
|
||||
};
|
||||
@@ -286,10 +285,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
if (reset_type == NONE)
|
||||
reset_type = MIXED; /* by default */
|
||||
|
||||
if ((reset_type == HARD || reset_type == MERGE)
|
||||
&& !is_inside_work_tree())
|
||||
die("%s reset requires a work tree",
|
||||
reset_type_names[reset_type]);
|
||||
if (reset_type == HARD || reset_type == MERGE)
|
||||
setup_work_tree();
|
||||
|
||||
/* Soft reset does not touch the index file nor the working tree
|
||||
* at all, but requires them in a good order. Other resets reset
|
||||
|
||||
@@ -322,7 +322,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
if (revs.bisect)
|
||||
bisect_list = 1;
|
||||
|
||||
quiet = DIFF_OPT_TST(&revs.diffopt, QUIET);
|
||||
quiet = DIFF_OPT_TST(&revs.diffopt, QUICK);
|
||||
for (i = 1 ; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ static int delete_tag(const char *name, const char *ref,
|
||||
{
|
||||
if (delete_ref(ref, sha1, 0))
|
||||
return 1;
|
||||
printf("Deleted tag '%s'\n", name);
|
||||
printf("Deleted tag '%s' (was %s)\n", name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -479,6 +479,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
die("%s: cannot lock the ref", ref);
|
||||
if (write_ref_sha1(lock, object, NULL) < 0)
|
||||
die("%s: cannot update the ref", ref);
|
||||
if (force && hashcmp(prev, object))
|
||||
printf("Updated tag '%s' (was %s)\n", tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
|
||||
|
||||
strbuf_release(&buf);
|
||||
return 0;
|
||||
|
||||
6
cache.h
6
cache.h
@@ -702,7 +702,11 @@ static inline unsigned int hexval(unsigned char c)
|
||||
#define DEFAULT_ABBREV 7
|
||||
|
||||
extern int get_sha1(const char *str, unsigned char *sha1);
|
||||
extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
|
||||
extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
|
||||
static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
|
||||
{
|
||||
return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
|
||||
}
|
||||
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||
|
||||
@@ -49,6 +49,7 @@ git-grep mainporcelain common
|
||||
git-gui mainporcelain
|
||||
git-hash-object plumbingmanipulators
|
||||
git-help ancillaryinterrogators
|
||||
git-http-backend synchingrepositories
|
||||
git-http-fetch synchelpers
|
||||
git-http-push synchelpers
|
||||
git-imap-send foreignscminterface
|
||||
|
||||
@@ -276,6 +276,9 @@ GIT_ARG_SET_PATH(shell)
|
||||
# Define PERL_PATH to provide path to Perl.
|
||||
GIT_ARG_SET_PATH(perl)
|
||||
#
|
||||
# Define PYTHON_PATH to provide path to Python.
|
||||
GIT_ARG_SET_PATH(python)
|
||||
#
|
||||
# Define ZLIB_PATH to provide path to zlib.
|
||||
GIT_ARG_SET_PATH(zlib)
|
||||
#
|
||||
|
||||
@@ -142,11 +142,9 @@ __git_ps1 ()
|
||||
elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
|
||||
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
|
||||
if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
|
||||
git diff --no-ext-diff --ignore-submodules \
|
||||
--quiet --exit-code || w="*"
|
||||
git diff --no-ext-diff --quiet --exit-code || w="*"
|
||||
if git rev-parse --quiet --verify HEAD >/dev/null; then
|
||||
git diff-index --cached --quiet \
|
||||
--ignore-submodules HEAD -- || i="+"
|
||||
git diff-index --cached --quiet HEAD -- || i="+"
|
||||
else
|
||||
i="#"
|
||||
fi
|
||||
@@ -163,11 +161,8 @@ __git_ps1 ()
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${1-}" ]; then
|
||||
printf "$1" "$c${b##refs/heads/}$w$i$s$u$r"
|
||||
else
|
||||
printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r"
|
||||
fi
|
||||
local f="$w$i$s$u"
|
||||
printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -2022,7 +2017,7 @@ _git_svn ()
|
||||
init fetch clone rebase dcommit log find-rev
|
||||
set-tree commit-diff info create-ignore propget
|
||||
proplist show-ignore show-externals branch tag blame
|
||||
migrate
|
||||
migrate mkdirs reset gc
|
||||
"
|
||||
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
||||
if [ -z "$subcommand" ]; then
|
||||
@@ -2069,7 +2064,7 @@ _git_svn ()
|
||||
__gitcomp "--stdin $cmt_opts $fc_opts"
|
||||
;;
|
||||
create-ignore,--*|propget,--*|proplist,--*|show-ignore,--*|\
|
||||
show-externals,--*)
|
||||
show-externals,--*|mkdirs,--*)
|
||||
__gitcomp "--revision="
|
||||
;;
|
||||
log,--*)
|
||||
@@ -2106,6 +2101,9 @@ _git_svn ()
|
||||
--no-auth-cache --username=
|
||||
"
|
||||
;;
|
||||
reset,--*)
|
||||
__gitcomp "--revision= --parent"
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
|
||||
28
daemon.c
28
daemon.c
@@ -562,6 +562,24 @@ static int execute(struct sockaddr *addr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int addrcmp(const struct sockaddr_storage *s1,
|
||||
const struct sockaddr_storage *s2)
|
||||
{
|
||||
if (s1->ss_family != s2->ss_family)
|
||||
return s1->ss_family - s2->ss_family;
|
||||
if (s1->ss_family == AF_INET)
|
||||
return memcmp(&((struct sockaddr_in *)s1)->sin_addr,
|
||||
&((struct sockaddr_in *)s2)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
#ifndef NO_IPV6
|
||||
if (s1->ss_family == AF_INET6)
|
||||
return memcmp(&((struct sockaddr_in6 *)s1)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)s2)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max_connections = 32;
|
||||
|
||||
static unsigned int live_children;
|
||||
@@ -576,17 +594,12 @@ static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
|
||||
{
|
||||
struct child *newborn, **cradle;
|
||||
|
||||
/*
|
||||
* This must be xcalloc() -- we'll compare the whole sockaddr_storage
|
||||
* but individual address may be shorter.
|
||||
*/
|
||||
newborn = xcalloc(1, sizeof(*newborn));
|
||||
live_children++;
|
||||
newborn->pid = pid;
|
||||
memcpy(&newborn->address, addr, addrlen);
|
||||
for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
|
||||
if (!memcmp(&(*cradle)->address, &newborn->address,
|
||||
sizeof(newborn->address)))
|
||||
if (!addrcmp(&(*cradle)->address, &newborn->address))
|
||||
break;
|
||||
newborn->next = *cradle;
|
||||
*cradle = newborn;
|
||||
@@ -619,8 +632,7 @@ static void kill_some_child(void)
|
||||
return;
|
||||
|
||||
for (; (next = blanket->next); blanket = next)
|
||||
if (!memcmp(&blanket->address, &next->address,
|
||||
sizeof(next->address))) {
|
||||
if (!addrcmp(&blanket->address, &next->address)) {
|
||||
kill(blanket->pid, SIGTERM);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int changed;
|
||||
|
||||
if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
|
||||
if (DIFF_OPT_TST(&revs->diffopt, QUICK) &&
|
||||
DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
|
||||
break;
|
||||
|
||||
@@ -507,7 +507,7 @@ int index_differs_from(const char *def, int diff_flags)
|
||||
|
||||
init_revisions(&rev, NULL);
|
||||
setup_revisions(0, NULL, &rev, def);
|
||||
DIFF_OPT_SET(&rev.diffopt, QUIET);
|
||||
DIFF_OPT_SET(&rev.diffopt, QUICK);
|
||||
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
|
||||
rev.diffopt.flags |= diff_flags;
|
||||
run_diff_index(&rev, 1);
|
||||
|
||||
75
diff.c
75
diff.c
@@ -194,6 +194,7 @@ struct emit_callback {
|
||||
struct diff_words_data *diff_words;
|
||||
int *found_changesp;
|
||||
FILE *file;
|
||||
struct strbuf *header;
|
||||
};
|
||||
|
||||
static int count_lines(const char *data, int size)
|
||||
@@ -797,6 +798,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
|
||||
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
|
||||
|
||||
if (ecbdata->header) {
|
||||
fprintf(ecbdata->file, "%s", ecbdata->header->buf);
|
||||
strbuf_reset(ecbdata->header);
|
||||
ecbdata->header = NULL;
|
||||
}
|
||||
*(ecbdata->found_changesp) = 1;
|
||||
|
||||
if (ecbdata->label_path[0]) {
|
||||
@@ -1601,6 +1607,7 @@ static void builtin_diff(const char *name_a,
|
||||
const char *reset = diff_get_color_opt(o, DIFF_RESET);
|
||||
const char *a_prefix, *b_prefix;
|
||||
const char *textconv_one = NULL, *textconv_two = NULL;
|
||||
struct strbuf header = STRBUF_INIT;
|
||||
|
||||
if (DIFF_OPT_TST(o, SUBMODULE_LOG) &&
|
||||
(!one->mode || S_ISGITLINK(one->mode)) &&
|
||||
@@ -1635,25 +1642,26 @@ static void builtin_diff(const char *name_a,
|
||||
b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
|
||||
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
|
||||
lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
|
||||
fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
|
||||
strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
|
||||
if (lbl[0][0] == '/') {
|
||||
/* /dev/null */
|
||||
fprintf(o->file, "%snew file mode %06o%s\n", set, two->mode, reset);
|
||||
strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset);
|
||||
if (xfrm_msg && xfrm_msg[0])
|
||||
fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
|
||||
strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
|
||||
}
|
||||
else if (lbl[1][0] == '/') {
|
||||
fprintf(o->file, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
|
||||
strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
|
||||
if (xfrm_msg && xfrm_msg[0])
|
||||
fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
|
||||
strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
|
||||
}
|
||||
else {
|
||||
if (one->mode != two->mode) {
|
||||
fprintf(o->file, "%sold mode %06o%s\n", set, one->mode, reset);
|
||||
fprintf(o->file, "%snew mode %06o%s\n", set, two->mode, reset);
|
||||
strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset);
|
||||
strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset);
|
||||
}
|
||||
if (xfrm_msg && xfrm_msg[0])
|
||||
fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
|
||||
strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
|
||||
|
||||
/*
|
||||
* we do not run diff between different kind
|
||||
* of objects.
|
||||
@@ -1663,6 +1671,8 @@ static void builtin_diff(const char *name_a,
|
||||
if (complete_rewrite &&
|
||||
(textconv_one || !diff_filespec_is_binary(one)) &&
|
||||
(textconv_two || !diff_filespec_is_binary(two))) {
|
||||
fprintf(o->file, "%s", header.buf);
|
||||
strbuf_reset(&header);
|
||||
emit_rewrite_diff(name_a, name_b, one, two,
|
||||
textconv_one, textconv_two, o);
|
||||
o->found_changes = 1;
|
||||
@@ -1680,6 +1690,8 @@ static void builtin_diff(const char *name_a,
|
||||
if (mf1.size == mf2.size &&
|
||||
!memcmp(mf1.ptr, mf2.ptr, mf1.size))
|
||||
goto free_ab_and_return;
|
||||
fprintf(o->file, "%s", header.buf);
|
||||
strbuf_reset(&header);
|
||||
if (DIFF_OPT_TST(o, BINARY))
|
||||
emit_binary_diff(o->file, &mf1, &mf2);
|
||||
else
|
||||
@@ -1696,6 +1708,11 @@ static void builtin_diff(const char *name_a,
|
||||
struct emit_callback ecbdata;
|
||||
const struct userdiff_funcname *pe;
|
||||
|
||||
if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS)) {
|
||||
fprintf(o->file, "%s", header.buf);
|
||||
strbuf_reset(&header);
|
||||
}
|
||||
|
||||
if (textconv_one) {
|
||||
size_t size;
|
||||
mf1.ptr = run_textconv(textconv_one, one, &size);
|
||||
@@ -1725,6 +1742,7 @@ static void builtin_diff(const char *name_a,
|
||||
if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
|
||||
check_blank_at_eof(&mf1, &mf2, &ecbdata);
|
||||
ecbdata.file = o->file;
|
||||
ecbdata.header = header.len ? &header : NULL;
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xecfg.ctxlen = o->context;
|
||||
xecfg.interhunkctxlen = o->interhunkcontext;
|
||||
@@ -1769,6 +1787,7 @@ static void builtin_diff(const char *name_a,
|
||||
}
|
||||
|
||||
free_ab_and_return:
|
||||
strbuf_release(&header);
|
||||
diff_free_filespec_data(one);
|
||||
diff_free_filespec_data(two);
|
||||
free(a_one);
|
||||
@@ -2551,6 +2570,20 @@ int diff_setup_done(struct diff_options *options)
|
||||
if (count > 1)
|
||||
die("--name-only, --name-status, --check and -s are mutually exclusive");
|
||||
|
||||
/*
|
||||
* Most of the time we can say "there are changes"
|
||||
* only by checking if there are changed paths, but
|
||||
* --ignore-whitespace* options force us to look
|
||||
* inside contents.
|
||||
*/
|
||||
|
||||
if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
|
||||
DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
|
||||
DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
|
||||
DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
|
||||
else
|
||||
DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);
|
||||
|
||||
if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
|
||||
options->detect_rename = DIFF_DETECT_COPY;
|
||||
|
||||
@@ -2611,7 +2644,7 @@ int diff_setup_done(struct diff_options *options)
|
||||
* to have found. It does not make sense not to return with
|
||||
* exit code in such a case either.
|
||||
*/
|
||||
if (DIFF_OPT_TST(options, QUIET)) {
|
||||
if (DIFF_OPT_TST(options, QUICK)) {
|
||||
options->output_format = DIFF_FORMAT_NO_OUTPUT;
|
||||
DIFF_OPT_SET(options, EXIT_WITH_STATUS);
|
||||
}
|
||||
@@ -2802,7 +2835,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
||||
else if (!strcmp(arg, "--exit-code"))
|
||||
DIFF_OPT_SET(options, EXIT_WITH_STATUS);
|
||||
else if (!strcmp(arg, "--quiet"))
|
||||
DIFF_OPT_SET(options, QUIET);
|
||||
DIFF_OPT_SET(options, QUICK);
|
||||
else if (!strcmp(arg, "--ext-diff"))
|
||||
DIFF_OPT_SET(options, ALLOW_EXTERNAL);
|
||||
else if (!strcmp(arg, "--no-ext-diff"))
|
||||
@@ -3509,6 +3542,18 @@ free_queue:
|
||||
q->nr = q->alloc = 0;
|
||||
if (options->close_file)
|
||||
fclose(options->file);
|
||||
|
||||
/*
|
||||
* Report the content-level differences with HAS_CHANGES;
|
||||
* diff_addremove/diff_change does not set the bit when
|
||||
* DIFF_FROM_CONTENTS is in effect (e.g. with -w).
|
||||
*/
|
||||
if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
|
||||
if (options->found_changes)
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
else
|
||||
DIFF_OPT_CLR(options, HAS_CHANGES);
|
||||
}
|
||||
}
|
||||
|
||||
static void diffcore_apply_filter(const char *filter)
|
||||
@@ -3645,7 +3690,7 @@ void diffcore_std(struct diff_options *options)
|
||||
diff_resolve_rename_copy();
|
||||
diffcore_apply_filter(options->filter);
|
||||
|
||||
if (diff_queued_diff.nr)
|
||||
if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
else
|
||||
DIFF_OPT_CLR(options, HAS_CHANGES);
|
||||
@@ -3705,7 +3750,8 @@ void diff_addremove(struct diff_options *options,
|
||||
fill_filespec(two, sha1, mode);
|
||||
|
||||
diff_queue(&diff_queued_diff, one, two);
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
}
|
||||
|
||||
void diff_change(struct diff_options *options,
|
||||
@@ -3737,7 +3783,8 @@ void diff_change(struct diff_options *options,
|
||||
fill_filespec(two, new_sha1, new_mode);
|
||||
|
||||
diff_queue(&diff_queued_diff, one, two);
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
}
|
||||
|
||||
void diff_unmerge(struct diff_options *options,
|
||||
@@ -3776,11 +3823,13 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
|
||||
if (start_command(&child) != 0 ||
|
||||
strbuf_read(&buf, child.out, 0) < 0 ||
|
||||
finish_command(&child) != 0) {
|
||||
close(child.out);
|
||||
strbuf_release(&buf);
|
||||
remove_tempfile();
|
||||
error("error running textconv command '%s'", pgm);
|
||||
return NULL;
|
||||
}
|
||||
close(child.out);
|
||||
remove_tempfile();
|
||||
|
||||
return strbuf_detach(&buf, outsize);
|
||||
|
||||
4
diff.h
4
diff.h
@@ -55,7 +55,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
||||
#define DIFF_OPT_COLOR_DIFF (1 << 8)
|
||||
#define DIFF_OPT_COLOR_DIFF_WORDS (1 << 9)
|
||||
#define DIFF_OPT_HAS_CHANGES (1 << 10)
|
||||
#define DIFF_OPT_QUIET (1 << 11)
|
||||
#define DIFF_OPT_QUICK (1 << 11)
|
||||
#define DIFF_OPT_NO_INDEX (1 << 12)
|
||||
#define DIFF_OPT_ALLOW_EXTERNAL (1 << 13)
|
||||
#define DIFF_OPT_EXIT_WITH_STATUS (1 << 14)
|
||||
@@ -66,7 +66,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
||||
#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19)
|
||||
#define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20)
|
||||
#define DIFF_OPT_ALLOW_TEXTCONV (1 << 21)
|
||||
|
||||
#define DIFF_OPT_DIFF_FROM_CONTENTS (1 << 22)
|
||||
#define DIFF_OPT_SUBMODULE_LOG (1 << 23)
|
||||
|
||||
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
|
||||
|
||||
@@ -19,8 +19,8 @@ Format of STDIN stream:
|
||||
|
||||
new_commit ::= 'commit' sp ref_str lf
|
||||
mark?
|
||||
('author' sp name sp '<' email '>' sp when lf)?
|
||||
'committer' sp name sp '<' email '>' sp when lf
|
||||
('author' (sp name)? sp '<' email '>' sp when lf)?
|
||||
'committer' (sp name)? sp '<' email '>' sp when lf
|
||||
commit_msg
|
||||
('from' sp committish lf)?
|
||||
('merge' sp committish lf)*
|
||||
@@ -47,7 +47,7 @@ Format of STDIN stream:
|
||||
|
||||
new_tag ::= 'tag' sp tag_str lf
|
||||
'from' sp committish lf
|
||||
('tagger' sp name sp '<' email '>' sp when lf)?
|
||||
('tagger' (sp name)? sp '<' email '>' sp when lf)?
|
||||
tag_msg;
|
||||
tag_msg ::= data;
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ $log->info("--------------- STARTING -----------------");
|
||||
my $usage =
|
||||
"Usage: git cvsserver [options] [pserver|server] [<directory> ...]\n".
|
||||
" --base-path <path> : Prepend to requested CVSROOT\n".
|
||||
" Can be read from GIT_CVSSERVER_BASE_PATH\n".
|
||||
" --strict-paths : Don't allow recursing into subdirectories\n".
|
||||
" --export-all : Don't check for gitcvs.enabled in config\n".
|
||||
" --version, -V : Print version information and exit\n".
|
||||
@@ -111,7 +112,8 @@ my $usage =
|
||||
"\n".
|
||||
"<directory> ... is a list of allowed directories. If no directories\n".
|
||||
"are given, all are allowed. This is an additional restriction, gitcvs\n".
|
||||
"access still needs to be enabled by the gitcvs.enabled config option.\n";
|
||||
"access still needs to be enabled by the gitcvs.enabled config option.\n".
|
||||
"Alternately, one directory may be specified in GIT_CVSSERVER_ROOT.\n";
|
||||
|
||||
my @opts = ( 'help|h|H', 'version|V',
|
||||
'base-path=s', 'strict-paths', 'export-all' );
|
||||
@@ -148,6 +150,24 @@ if ($state->{'export-all'} && !@{$state->{allowed_roots}}) {
|
||||
die "--export-all can only be used together with an explicit whitelist\n";
|
||||
}
|
||||
|
||||
# Environment handling for running under git-shell
|
||||
if (exists $ENV{GIT_CVSSERVER_BASE_PATH}) {
|
||||
if ($state->{'base-path'}) {
|
||||
die "Cannot specify base path both ways.\n";
|
||||
}
|
||||
my $base_path = $ENV{GIT_CVSSERVER_BASE_PATH};
|
||||
$state->{'base-path'} = $base_path;
|
||||
$log->debug("Picked up base path '$base_path' from environment.\n");
|
||||
}
|
||||
if (exists $ENV{GIT_CVSSERVER_ROOT}) {
|
||||
if (@{$state->{allowed_roots}}) {
|
||||
die "Cannot specify roots both ways: @ARGV\n";
|
||||
}
|
||||
my $allowed_root = $ENV{GIT_CVSSERVER_ROOT};
|
||||
$state->{allowed_roots} = [ $allowed_root ];
|
||||
$log->debug("Picked up allowed root '$allowed_root' from environment.\n");
|
||||
}
|
||||
|
||||
# if we are called with a pserver argument,
|
||||
# deal with the authentication cat before entering the
|
||||
# main loop
|
||||
@@ -981,6 +1001,8 @@ sub req_update
|
||||
|
||||
#$log->debug("update state : " . Dumper($state));
|
||||
|
||||
my $last_dirname = "///";
|
||||
|
||||
# foreach file specified on the command line ...
|
||||
foreach my $filename ( @{$state->{args}} )
|
||||
{
|
||||
@@ -988,6 +1010,20 @@ sub req_update
|
||||
|
||||
$log->debug("Processing file $filename");
|
||||
|
||||
unless ( $state->{globaloptions}{-Q} || $state->{globaloptions}{-q} )
|
||||
{
|
||||
my $cur_dirname = dirname($filename);
|
||||
if ( $cur_dirname ne $last_dirname )
|
||||
{
|
||||
$last_dirname = $cur_dirname;
|
||||
if ( $cur_dirname eq "" )
|
||||
{
|
||||
$cur_dirname = ".";
|
||||
}
|
||||
print "E cvs update: Updating $cur_dirname\n";
|
||||
}
|
||||
}
|
||||
|
||||
# if we have a -C we should pretend we never saw modified stuff
|
||||
if ( exists ( $state->{opt}{C} ) )
|
||||
{
|
||||
|
||||
@@ -259,7 +259,6 @@ test -s "$tempdir"/heads ||
|
||||
|
||||
GIT_INDEX_FILE="$(pwd)/../index"
|
||||
export GIT_INDEX_FILE
|
||||
git read-tree || die "Could not seed the index"
|
||||
|
||||
# map old->new commit ids for rewriting parents
|
||||
mkdir ../map || die "Could not create map/ directory"
|
||||
|
||||
@@ -44,9 +44,8 @@ esac
|
||||
# MRC is the current "merge reference commit"
|
||||
# MRT is the current "merge result tree"
|
||||
|
||||
MRC=$head MSG= PARENT="-p $head"
|
||||
MRC=$(git rev-parse --verify -q $head)
|
||||
MRT=$(git write-tree)
|
||||
CNT=1 ;# counting our head
|
||||
NON_FF_MERGE=0
|
||||
OCTOPUS_FAILURE=0
|
||||
for SHA1 in $remotes
|
||||
@@ -61,19 +60,17 @@ do
|
||||
exit 2
|
||||
esac
|
||||
|
||||
eval pretty_name=\${GITHEAD_$SHA1:-$SHA1}
|
||||
common=$(git merge-base --all $SHA1 $MRC) ||
|
||||
die "Unable to find common commit with $SHA1"
|
||||
die "Unable to find common commit with $pretty_name"
|
||||
|
||||
case "$LF$common$LF" in
|
||||
*"$LF$SHA1$LF"*)
|
||||
echo "Already up-to-date with $SHA1"
|
||||
echo "Already up-to-date with $pretty_name"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
CNT=`expr $CNT + 1`
|
||||
PARENT="$PARENT -p $SHA1"
|
||||
|
||||
if test "$common,$NON_FF_MERGE" = "$MRC,0"
|
||||
then
|
||||
# The first head being merged was a fast-forward.
|
||||
@@ -81,7 +78,7 @@ do
|
||||
# tree as the intermediate result of the merge.
|
||||
# We still need to count this as part of the parent set.
|
||||
|
||||
echo "Fast-forwarding to: $SHA1"
|
||||
echo "Fast-forwarding to: $pretty_name"
|
||||
git read-tree -u -m $head $SHA1 || exit
|
||||
MRC=$SHA1 MRT=$(git write-tree)
|
||||
continue
|
||||
@@ -89,7 +86,7 @@ do
|
||||
|
||||
NON_FF_MERGE=1
|
||||
|
||||
echo "Trying simple merge with $SHA1"
|
||||
echo "Trying simple merge with $pretty_name"
|
||||
git read-tree -u -m --aggressive $common $MRT $SHA1 || exit 2
|
||||
next=$(git write-tree 2>/dev/null)
|
||||
if test $? -ne 0
|
||||
|
||||
@@ -71,7 +71,7 @@ git send-email [options] <file | directory | rev-list options >
|
||||
--suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, all.
|
||||
--[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on.
|
||||
--[no-]suppress-from * Send to self. Default off.
|
||||
--[no-]chain-reply-to * Chain In-Reply-To: fields. Default on.
|
||||
--[no-]chain-reply-to * Chain In-Reply-To: fields. Default off.
|
||||
--[no-]thread * Use In-Reply-To: field. Default on.
|
||||
|
||||
Administering:
|
||||
@@ -221,10 +221,10 @@ sub chain_reply_to {
|
||||
if (defined $chain_reply_to &&
|
||||
$chain_reply_to eq $not_set_by_user) {
|
||||
print STDERR
|
||||
"In git 1.7.0, the default will be changed to --no-chain-reply-to\n" .
|
||||
"In git 1.7.0, the default has changed to --no-chain-reply-to\n" .
|
||||
"Set sendemail.chainreplyto configuration variable to true if\n" .
|
||||
"you want to keep --chain-reply-to as your default.\n";
|
||||
$chain_reply_to = 1;
|
||||
$chain_reply_to = 0;
|
||||
}
|
||||
return $chain_reply_to;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ USAGE="list [<options>]
|
||||
or: $dashless drop [-q|--quiet] [<stash>]
|
||||
or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
|
||||
or: $dashless branch <branchname> [<stash>]
|
||||
or: $dashless [save [-k|--keep-index] [-q|--quiet] [<message>]]
|
||||
or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] [<message>]]
|
||||
or: $dashless clear"
|
||||
|
||||
SUBDIRECTORY_OK=Yes
|
||||
|
||||
2
git_remote_helpers/.gitignore
vendored
Normal file
2
git_remote_helpers/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/dist
|
||||
35
git_remote_helpers/Makefile
Normal file
35
git_remote_helpers/Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# Makefile for the git_remote_helpers python support modules
|
||||
#
|
||||
pysetupfile:=setup.py
|
||||
|
||||
# Shell quote (do not use $(call) to accommodate ancient setups);
|
||||
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
|
||||
|
||||
ifndef PYTHON_PATH
|
||||
PYTHON_PATH = /usr/bin/python
|
||||
endif
|
||||
ifndef prefix
|
||||
prefix = $(HOME)
|
||||
endif
|
||||
ifndef V
|
||||
QUIET = @
|
||||
QUIETSETUP = --quiet
|
||||
endif
|
||||
|
||||
PYLIBDIR=$(shell $(PYTHON_PATH) -c \
|
||||
"import sys; \
|
||||
print 'lib/python%i.%i/site-packages' % sys.version_info[:2]")
|
||||
|
||||
all: $(pysetupfile)
|
||||
$(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build
|
||||
|
||||
install: $(pysetupfile)
|
||||
$(PYTHON_PATH) $(pysetupfile) install --prefix $(DESTDIR_SQ)$(prefix)
|
||||
|
||||
instlibdir: $(pysetupfile)
|
||||
@echo "$(DESTDIR_SQ)$(prefix)/$(PYLIBDIR)"
|
||||
|
||||
clean:
|
||||
$(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) clean -a
|
||||
$(RM) *.pyo *.pyc
|
||||
16
git_remote_helpers/__init__.py
Normal file
16
git_remote_helpers/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Support library package for git remote helpers.
|
||||
|
||||
Git remote helpers are helper commands that interfaces with a non-git
|
||||
repository to provide automatic import of non-git history into a Git
|
||||
repository.
|
||||
|
||||
This package provides the support library needed by these helpers..
|
||||
The following modules are included:
|
||||
|
||||
- git.git - Interaction with Git repositories
|
||||
|
||||
- util - General utility functionality use by the other modules in
|
||||
this package, and also used directly by the helpers.
|
||||
"""
|
||||
0
git_remote_helpers/git/__init__.py
Normal file
0
git_remote_helpers/git/__init__.py
Normal file
678
git_remote_helpers/git/git.py
Normal file
678
git_remote_helpers/git/git.py
Normal file
@@ -0,0 +1,678 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Functionality for interacting with Git repositories.
|
||||
|
||||
This module provides classes for interfacing with a Git repository.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from binascii import hexlify
|
||||
from cStringIO import StringIO
|
||||
import unittest
|
||||
|
||||
from git_remote_helpers.util import debug, error, die, start_command, run_command
|
||||
|
||||
|
||||
def get_git_dir ():
|
||||
"""Return the path to the GIT_DIR for this repo."""
|
||||
args = ("git", "rev-parse", "--git-dir")
|
||||
exit_code, output, errors = run_command(args)
|
||||
if exit_code:
|
||||
die("Failed to retrieve git dir")
|
||||
assert not errors
|
||||
return output.strip()
|
||||
|
||||
|
||||
def parse_git_config ():
|
||||
"""Return a dict containing the parsed version of 'git config -l'."""
|
||||
exit_code, output, errors = run_command(("git", "config", "-z", "-l"))
|
||||
if exit_code:
|
||||
die("Failed to retrieve git configuration")
|
||||
assert not errors
|
||||
return dict([e.split('\n', 1) for e in output.split("\0") if e])
|
||||
|
||||
|
||||
def git_config_bool (value):
|
||||
"""Convert the given git config string value to True or False.
|
||||
|
||||
Raise ValueError if the given string was not recognized as a
|
||||
boolean value.
|
||||
|
||||
"""
|
||||
norm_value = str(value).strip().lower()
|
||||
if norm_value in ("true", "1", "yes", "on", ""):
|
||||
return True
|
||||
if norm_value in ("false", "0", "no", "off", "none"):
|
||||
return False
|
||||
raise ValueError("Failed to parse '%s' into a boolean value" % (value))
|
||||
|
||||
|
||||
def valid_git_ref (ref_name):
|
||||
"""Return True iff the given ref name is a valid git ref name."""
|
||||
# The following is a reimplementation of the git check-ref-format
|
||||
# command. The rules were derived from the git check-ref-format(1)
|
||||
# manual page. This code should be replaced by a call to
|
||||
# check_ref_format() in the git library, when such is available.
|
||||
if ref_name.endswith('/') or \
|
||||
ref_name.startswith('.') or \
|
||||
ref_name.count('/.') or \
|
||||
ref_name.count('..') or \
|
||||
ref_name.endswith('.lock'):
|
||||
return False
|
||||
for c in ref_name:
|
||||
if ord(c) < 0x20 or ord(c) == 0x7f or c in " ~^:?*[":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class GitObjectFetcher(object):
|
||||
|
||||
"""Provide parsed access to 'git cat-file --batch'.
|
||||
|
||||
This provides a read-only interface to the Git object database.
|
||||
|
||||
"""
|
||||
|
||||
def __init__ (self):
|
||||
"""Initiate a 'git cat-file --batch' session."""
|
||||
self.queue = [] # List of object names to be submitted
|
||||
self.in_transit = None # Object name currently in transit
|
||||
|
||||
# 'git cat-file --batch' produces binary output which is likely
|
||||
# to be corrupted by the default "rU"-mode pipe opened by
|
||||
# start_command. (Mode == "rU" does universal new-line
|
||||
# conversion, which mangles carriage returns.) Therefore, we
|
||||
# open an explicitly binary-safe pipe for transferring the
|
||||
# output from 'git cat-file --batch'.
|
||||
pipe_r_fd, pipe_w_fd = os.pipe()
|
||||
pipe_r = os.fdopen(pipe_r_fd, "rb")
|
||||
pipe_w = os.fdopen(pipe_w_fd, "wb")
|
||||
self.proc = start_command(("git", "cat-file", "--batch"),
|
||||
stdout = pipe_w)
|
||||
self.f = pipe_r
|
||||
|
||||
def __del__ (self):
|
||||
"""Verify completed communication with 'git cat-file --batch'."""
|
||||
assert not self.queue
|
||||
assert self.in_transit is None
|
||||
self.proc.stdin.close()
|
||||
assert self.proc.wait() == 0 # Zero exit code
|
||||
assert self.f.read() == "" # No remaining output
|
||||
|
||||
def _submit_next_object (self):
|
||||
"""Submit queue items to the 'git cat-file --batch' process.
|
||||
|
||||
If there are items in the queue, and there is currently no item
|
||||
currently in 'transit', then pop the first item off the queue,
|
||||
and submit it.
|
||||
|
||||
"""
|
||||
if self.queue and self.in_transit is None:
|
||||
self.in_transit = self.queue.pop(0)
|
||||
print >> self.proc.stdin, self.in_transit[0]
|
||||
|
||||
def push (self, obj, callback):
|
||||
"""Push the given object name onto the queue.
|
||||
|
||||
The given callback function will at some point in the future
|
||||
be called exactly once with the following arguments:
|
||||
- self - this GitObjectFetcher instance
|
||||
- obj - the object name provided to push()
|
||||
- sha1 - the SHA1 of the object, if 'None' obj is missing
|
||||
- t - the type of the object (tag/commit/tree/blob)
|
||||
- size - the size of the object in bytes
|
||||
- data - the object contents
|
||||
|
||||
"""
|
||||
self.queue.append((obj, callback))
|
||||
self._submit_next_object() # (Re)start queue processing
|
||||
|
||||
def process_next_entry (self):
|
||||
"""Read the next entry off the queue and invoke callback."""
|
||||
obj, cb = self.in_transit
|
||||
self.in_transit = None
|
||||
header = self.f.readline()
|
||||
if header == "%s missing\n" % (obj):
|
||||
cb(self, obj, None, None, None, None)
|
||||
return
|
||||
sha1, t, size = header.split(" ")
|
||||
assert len(sha1) == 40
|
||||
assert t in ("tag", "commit", "tree", "blob")
|
||||
assert size.endswith("\n")
|
||||
size = int(size.strip())
|
||||
data = self.f.read(size)
|
||||
assert self.f.read(1) == "\n"
|
||||
cb(self, obj, sha1, t, size, data)
|
||||
self._submit_next_object()
|
||||
|
||||
def process (self):
|
||||
"""Process the current queue until empty."""
|
||||
while self.in_transit is not None:
|
||||
self.process_next_entry()
|
||||
|
||||
# High-level convenience methods:
|
||||
|
||||
def get_sha1 (self, objspec):
|
||||
"""Return the SHA1 of the object specified by 'objspec'.
|
||||
|
||||
Return None if 'objspec' does not specify an existing object.
|
||||
|
||||
"""
|
||||
class _ObjHandler(object):
|
||||
"""Helper class for getting the returned SHA1."""
|
||||
def __init__ (self, parser):
|
||||
self.parser = parser
|
||||
self.sha1 = None
|
||||
|
||||
def __call__ (self, parser, obj, sha1, t, size, data):
|
||||
# FIXME: Many unused arguments. Could this be cheaper?
|
||||
assert parser == self.parser
|
||||
self.sha1 = sha1
|
||||
|
||||
handler = _ObjHandler(self)
|
||||
self.push(objspec, handler)
|
||||
self.process()
|
||||
return handler.sha1
|
||||
|
||||
def open_obj (self, objspec):
|
||||
"""Return a file object wrapping the contents of a named object.
|
||||
|
||||
The caller is responsible for calling .close() on the returned
|
||||
file object.
|
||||
|
||||
Raise KeyError if 'objspec' does not exist in the repo.
|
||||
|
||||
"""
|
||||
class _ObjHandler(object):
|
||||
"""Helper class for parsing the returned git object."""
|
||||
def __init__ (self, parser):
|
||||
"""Set up helper."""
|
||||
self.parser = parser
|
||||
self.contents = StringIO()
|
||||
self.err = None
|
||||
|
||||
def __call__ (self, parser, obj, sha1, t, size, data):
|
||||
"""Git object callback (see GitObjectFetcher documentation)."""
|
||||
assert parser == self.parser
|
||||
if not sha1: # Missing object
|
||||
self.err = "Missing object '%s'" % obj
|
||||
else:
|
||||
assert size == len(data)
|
||||
self.contents.write(data)
|
||||
|
||||
handler = _ObjHandler(self)
|
||||
self.push(objspec, handler)
|
||||
self.process()
|
||||
if handler.err:
|
||||
raise KeyError(handler.err)
|
||||
handler.contents.seek(0)
|
||||
return handler.contents
|
||||
|
||||
def walk_tree (self, tree_objspec, callback, prefix = ""):
|
||||
"""Recursively walk the given Git tree object.
|
||||
|
||||
Recursively walk all subtrees of the given tree object, and
|
||||
invoke the given callback passing three arguments:
|
||||
(path, mode, data) with the path, permission bits, and contents
|
||||
of all the blobs found in the entire tree structure.
|
||||
|
||||
"""
|
||||
class _ObjHandler(object):
|
||||
"""Helper class for walking a git tree structure."""
|
||||
def __init__ (self, parser, cb, path, mode = None):
|
||||
"""Set up helper."""
|
||||
self.parser = parser
|
||||
self.cb = cb
|
||||
self.path = path
|
||||
self.mode = mode
|
||||
self.err = None
|
||||
|
||||
def parse_tree (self, treedata):
|
||||
"""Parse tree object data, yield tree entries.
|
||||
|
||||
Each tree entry is a 3-tuple (mode, sha1, path)
|
||||
|
||||
self.path is prepended to all paths yielded
|
||||
from this method.
|
||||
|
||||
"""
|
||||
while treedata:
|
||||
mode = int(treedata[:6], 10)
|
||||
# Turn 100xxx into xxx
|
||||
if mode > 100000:
|
||||
mode -= 100000
|
||||
assert treedata[6] == " "
|
||||
i = treedata.find("\0", 7)
|
||||
assert i > 0
|
||||
path = treedata[7:i]
|
||||
sha1 = hexlify(treedata[i + 1: i + 21])
|
||||
yield (mode, sha1, self.path + path)
|
||||
treedata = treedata[i + 21:]
|
||||
|
||||
def __call__ (self, parser, obj, sha1, t, size, data):
|
||||
"""Git object callback (see GitObjectFetcher documentation)."""
|
||||
assert parser == self.parser
|
||||
if not sha1: # Missing object
|
||||
self.err = "Missing object '%s'" % (obj)
|
||||
return
|
||||
assert size == len(data)
|
||||
if t == "tree":
|
||||
if self.path:
|
||||
self.path += "/"
|
||||
# Recurse into all blobs and subtrees
|
||||
for m, s, p in self.parse_tree(data):
|
||||
parser.push(s,
|
||||
self.__class__(self.parser, self.cb, p, m))
|
||||
elif t == "blob":
|
||||
self.cb(self.path, self.mode, data)
|
||||
else:
|
||||
raise ValueError("Unknown object type '%s'" % (t))
|
||||
|
||||
self.push(tree_objspec, _ObjHandler(self, callback, prefix))
|
||||
self.process()
|
||||
|
||||
|
||||
class GitRefMap(object):
|
||||
|
||||
"""Map Git ref names to the Git object names they currently point to.
|
||||
|
||||
Behaves like a dictionary of Git ref names -> Git object names.
|
||||
|
||||
"""
|
||||
|
||||
def __init__ (self, obj_fetcher):
|
||||
"""Create a new Git ref -> object map."""
|
||||
self.obj_fetcher = obj_fetcher
|
||||
self._cache = {} # dict: refname -> objname
|
||||
|
||||
def _load (self, ref):
|
||||
"""Retrieve the object currently bound to the given ref.
|
||||
|
||||
The name of the object pointed to by the given ref is stored
|
||||
into this mapping, and also returned.
|
||||
|
||||
"""
|
||||
if ref not in self._cache:
|
||||
self._cache[ref] = self.obj_fetcher.get_sha1(ref)
|
||||
return self._cache[ref]
|
||||
|
||||
def __contains__ (self, refname):
|
||||
"""Return True if the given refname is present in this cache."""
|
||||
return bool(self._load(refname))
|
||||
|
||||
def __getitem__ (self, refname):
|
||||
"""Return the git object name pointed to by the given refname."""
|
||||
commit = self._load(refname)
|
||||
if commit is None:
|
||||
raise KeyError("Unknown ref '%s'" % (refname))
|
||||
return commit
|
||||
|
||||
def get (self, refname, default = None):
|
||||
"""Return the git object name pointed to by the given refname."""
|
||||
commit = self._load(refname)
|
||||
if commit is None:
|
||||
return default
|
||||
return commit
|
||||
|
||||
|
||||
class GitFICommit(object):
|
||||
|
||||
"""Encapsulate the data in a Git fast-import commit command."""
|
||||
|
||||
SHA1RE = re.compile(r'^[0-9a-f]{40}$')
|
||||
|
||||
@classmethod
|
||||
def parse_mode (cls, mode):
|
||||
"""Verify the given git file mode, and return it as a string."""
|
||||
assert mode in (644, 755, 100644, 100755, 120000)
|
||||
return "%i" % (mode)
|
||||
|
||||
@classmethod
|
||||
def parse_objname (cls, objname):
|
||||
"""Return the given object name (or mark number) as a string."""
|
||||
if isinstance(objname, int): # Object name is a mark number
|
||||
assert objname > 0
|
||||
return ":%i" % (objname)
|
||||
|
||||
# No existence check is done, only checks for valid format
|
||||
assert cls.SHA1RE.match(objname) # Object name is valid SHA1
|
||||
return objname
|
||||
|
||||
@classmethod
|
||||
def quote_path (cls, path):
|
||||
"""Return a quoted version of the given path."""
|
||||
path = path.replace("\\", "\\\\")
|
||||
path = path.replace("\n", "\\n")
|
||||
path = path.replace('"', '\\"')
|
||||
return '"%s"' % (path)
|
||||
|
||||
@classmethod
|
||||
def parse_path (cls, path):
|
||||
"""Verify that the given path is valid, and quote it, if needed."""
|
||||
assert not isinstance(path, int) # Cannot be a mark number
|
||||
|
||||
# These checks verify the rules on the fast-import man page
|
||||
assert not path.count("//")
|
||||
assert not path.endswith("/")
|
||||
assert not path.startswith("/")
|
||||
assert not path.count("/./")
|
||||
assert not path.count("/../")
|
||||
assert not path.endswith("/.")
|
||||
assert not path.endswith("/..")
|
||||
assert not path.startswith("./")
|
||||
assert not path.startswith("../")
|
||||
|
||||
if path.count('"') + path.count('\n') + path.count('\\'):
|
||||
return cls.quote_path(path)
|
||||
return path
|
||||
|
||||
def __init__ (self, name, email, timestamp, timezone, message):
|
||||
"""Create a new Git fast-import commit, with the given metadata."""
|
||||
self.name = name
|
||||
self.email = email
|
||||
self.timestamp = timestamp
|
||||
self.timezone = timezone
|
||||
self.message = message
|
||||
self.pathops = [] # List of path operations in this commit
|
||||
|
||||
def modify (self, mode, blobname, path):
|
||||
"""Add a file modification to this Git fast-import commit."""
|
||||
self.pathops.append(("M",
|
||||
self.parse_mode(mode),
|
||||
self.parse_objname(blobname),
|
||||
self.parse_path(path)))
|
||||
|
||||
def delete (self, path):
|
||||
"""Add a file deletion to this Git fast-import commit."""
|
||||
self.pathops.append(("D", self.parse_path(path)))
|
||||
|
||||
def copy (self, path, newpath):
|
||||
"""Add a file copy to this Git fast-import commit."""
|
||||
self.pathops.append(("C",
|
||||
self.parse_path(path),
|
||||
self.parse_path(newpath)))
|
||||
|
||||
def rename (self, path, newpath):
|
||||
"""Add a file rename to this Git fast-import commit."""
|
||||
self.pathops.append(("R",
|
||||
self.parse_path(path),
|
||||
self.parse_path(newpath)))
|
||||
|
||||
def note (self, blobname, commit):
|
||||
"""Add a note object to this Git fast-import commit."""
|
||||
self.pathops.append(("N",
|
||||
self.parse_objname(blobname),
|
||||
self.parse_objname(commit)))
|
||||
|
||||
def deleteall (self):
|
||||
"""Delete all files in this Git fast-import commit."""
|
||||
self.pathops.append("deleteall")
|
||||
|
||||
|
||||
class TestGitFICommit(unittest.TestCase):
|
||||
|
||||
"""GitFICommit selftests."""
|
||||
|
||||
def test_basic (self):
|
||||
"""GitFICommit basic selftests."""
|
||||
|
||||
def expect_fail (method, data):
|
||||
"""Verify that the method(data) raises an AssertionError."""
|
||||
try:
|
||||
method(data)
|
||||
except AssertionError:
|
||||
return
|
||||
raise AssertionError("Failed test for invalid data '%s(%s)'" %
|
||||
(method.__name__, repr(data)))
|
||||
|
||||
def test_parse_mode (self):
|
||||
"""GitFICommit.parse_mode() selftests."""
|
||||
self.assertEqual(GitFICommit.parse_mode(644), "644")
|
||||
self.assertEqual(GitFICommit.parse_mode(755), "755")
|
||||
self.assertEqual(GitFICommit.parse_mode(100644), "100644")
|
||||
self.assertEqual(GitFICommit.parse_mode(100755), "100755")
|
||||
self.assertEqual(GitFICommit.parse_mode(120000), "120000")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_mode, 0)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_mode, 123)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_mode, 600)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_mode, "644")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_mode, "abc")
|
||||
|
||||
def test_parse_objname (self):
|
||||
"""GitFICommit.parse_objname() selftests."""
|
||||
self.assertEqual(GitFICommit.parse_objname(1), ":1")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_objname, 0)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_objname, -1)
|
||||
self.assertEqual(GitFICommit.parse_objname("0123456789" * 4),
|
||||
"0123456789" * 4)
|
||||
self.assertEqual(GitFICommit.parse_objname("2468abcdef" * 4),
|
||||
"2468abcdef" * 4)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_objname,
|
||||
"abcdefghij" * 4)
|
||||
|
||||
def test_parse_path (self):
|
||||
"""GitFICommit.parse_path() selftests."""
|
||||
self.assertEqual(GitFICommit.parse_path("foo/bar"), "foo/bar")
|
||||
self.assertEqual(GitFICommit.parse_path("path/with\n and \" in it"),
|
||||
'"path/with\\n and \\" in it"')
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, 1)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, 0)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, -1)
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "foo//bar")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "/foo/bar")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/./bar")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/../bar")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/.")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/..")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "./foo/bar")
|
||||
self.assertRaises(AssertionError, GitFICommit.parse_path, "../foo/bar")
|
||||
|
||||
|
||||
class GitFastImport(object):
|
||||
|
||||
"""Encapsulate communication with git fast-import."""
|
||||
|
||||
def __init__ (self, f, obj_fetcher, last_mark = 0):
|
||||
"""Set up self to communicate with a fast-import process through f."""
|
||||
self.f = f # File object where fast-import stream is written
|
||||
self.obj_fetcher = obj_fetcher # GitObjectFetcher instance
|
||||
self.next_mark = last_mark + 1 # Next mark number
|
||||
self.refs = set() # Keep track of the refnames we've seen
|
||||
|
||||
def comment (self, s):
|
||||
"""Write the given comment in the fast-import stream."""
|
||||
assert "\n" not in s, "Malformed comment: '%s'" % (s)
|
||||
self.f.write("# %s\n" % (s))
|
||||
|
||||
def commit (self, ref, commitdata):
|
||||
"""Make a commit on the given ref, with the given GitFICommit.
|
||||
|
||||
Return the mark number identifying this commit.
|
||||
|
||||
"""
|
||||
self.f.write("""\
|
||||
commit %(ref)s
|
||||
mark :%(mark)i
|
||||
committer %(name)s <%(email)s> %(timestamp)i %(timezone)s
|
||||
data %(msgLength)i
|
||||
%(msg)s
|
||||
""" % {
|
||||
'ref': ref,
|
||||
'mark': self.next_mark,
|
||||
'name': commitdata.name,
|
||||
'email': commitdata.email,
|
||||
'timestamp': commitdata.timestamp,
|
||||
'timezone': commitdata.timezone,
|
||||
'msgLength': len(commitdata.message),
|
||||
'msg': commitdata.message,
|
||||
})
|
||||
|
||||
if ref not in self.refs:
|
||||
self.refs.add(ref)
|
||||
parent = ref + "^0"
|
||||
if self.obj_fetcher.get_sha1(parent):
|
||||
self.f.write("from %s\n" % (parent))
|
||||
|
||||
for op in commitdata.pathops:
|
||||
self.f.write(" ".join(op))
|
||||
self.f.write("\n")
|
||||
self.f.write("\n")
|
||||
retval = self.next_mark
|
||||
self.next_mark += 1
|
||||
return retval
|
||||
|
||||
def blob (self, data):
|
||||
"""Import the given blob.
|
||||
|
||||
Return the mark number identifying this blob.
|
||||
|
||||
"""
|
||||
self.f.write("blob\nmark :%i\ndata %i\n%s\n" %
|
||||
(self.next_mark, len(data), data))
|
||||
retval = self.next_mark
|
||||
self.next_mark += 1
|
||||
return retval
|
||||
|
||||
def reset (self, ref, objname):
|
||||
"""Reset the given ref to point at the given Git object."""
|
||||
self.f.write("reset %s\nfrom %s\n\n" %
|
||||
(ref, GitFICommit.parse_objname(objname)))
|
||||
if ref not in self.refs:
|
||||
self.refs.add(ref)
|
||||
|
||||
|
||||
class GitNotes(object):
|
||||
|
||||
"""Encapsulate access to Git notes.
|
||||
|
||||
Simulates a dictionary of object name (SHA1) -> Git note mappings.
|
||||
|
||||
"""
|
||||
|
||||
def __init__ (self, notes_ref, obj_fetcher):
|
||||
"""Create a new Git notes interface, bound to the given notes ref."""
|
||||
self.notes_ref = notes_ref
|
||||
self.obj_fetcher = obj_fetcher # Used to get objects from repo
|
||||
self.imports = [] # list: (objname, note data blob name) tuples
|
||||
|
||||
def __del__ (self):
|
||||
"""Verify that self.commit_notes() was called before destruction."""
|
||||
if self.imports:
|
||||
error("Missing call to self.commit_notes().")
|
||||
error("%i notes are not committed!", len(self.imports))
|
||||
|
||||
def _load (self, objname):
|
||||
"""Return the note data associated with the given git object.
|
||||
|
||||
The note data is returned in string form. If no note is found
|
||||
for the given object, None is returned.
|
||||
|
||||
"""
|
||||
try:
|
||||
f = self.obj_fetcher.open_obj("%s:%s" % (self.notes_ref, objname))
|
||||
ret = f.read()
|
||||
f.close()
|
||||
except KeyError:
|
||||
ret = None
|
||||
return ret
|
||||
|
||||
def __getitem__ (self, objname):
|
||||
"""Return the note contents associated with the given object.
|
||||
|
||||
Raise KeyError if given object has no associated note.
|
||||
|
||||
"""
|
||||
blobdata = self._load(objname)
|
||||
if blobdata is None:
|
||||
raise KeyError("Object '%s' has no note" % (objname))
|
||||
return blobdata
|
||||
|
||||
def get (self, objname, default = None):
|
||||
"""Return the note contents associated with the given object.
|
||||
|
||||
Return given default if given object has no associated note.
|
||||
|
||||
"""
|
||||
blobdata = self._load(objname)
|
||||
if blobdata is None:
|
||||
return default
|
||||
return blobdata
|
||||
|
||||
def import_note (self, objname, data, gfi):
|
||||
"""Tell git fast-import to store data as a note for objname.
|
||||
|
||||
This method uses the given GitFastImport object to create a
|
||||
blob containing the given note data. Also an entry mapping the
|
||||
given object name to the created blob is stored until
|
||||
commit_notes() is called.
|
||||
|
||||
Note that this method only works if it is later followed by a
|
||||
call to self.commit_notes() (which produces the note commit
|
||||
that refers to the blob produced here).
|
||||
|
||||
"""
|
||||
if not data.endswith("\n"):
|
||||
data += "\n"
|
||||
gfi.comment("Importing note for object %s" % (objname))
|
||||
mark = gfi.blob(data)
|
||||
self.imports.append((objname, mark))
|
||||
|
||||
def commit_notes (self, gfi, author, message):
|
||||
"""Produce a git fast-import note commit for the imported notes.
|
||||
|
||||
This method uses the given GitFastImport object to create a
|
||||
commit on the notes ref, introducing the notes previously
|
||||
submitted to import_note().
|
||||
|
||||
"""
|
||||
if not self.imports:
|
||||
return
|
||||
commitdata = GitFICommit(author[0], author[1],
|
||||
time.time(), "0000", message)
|
||||
for objname, blobname in self.imports:
|
||||
assert isinstance(objname, int) and objname > 0
|
||||
assert isinstance(blobname, int) and blobname > 0
|
||||
commitdata.note(blobname, objname)
|
||||
gfi.commit(self.notes_ref, commitdata)
|
||||
self.imports = []
|
||||
|
||||
|
||||
class GitCachedNotes(GitNotes):
|
||||
|
||||
"""Encapsulate access to Git notes (cached version).
|
||||
|
||||
Only use this class if no caching is done at a higher level.
|
||||
|
||||
Simulates a dictionary of object name (SHA1) -> Git note mappings.
|
||||
|
||||
"""
|
||||
|
||||
def __init__ (self, notes_ref, obj_fetcher):
|
||||
"""Set up a caching wrapper around GitNotes."""
|
||||
GitNotes.__init__(self, notes_ref, obj_fetcher)
|
||||
self._cache = {} # Cache: object name -> note data
|
||||
|
||||
def __del__ (self):
|
||||
"""Verify that GitNotes' destructor is called."""
|
||||
GitNotes.__del__(self)
|
||||
|
||||
def _load (self, objname):
|
||||
"""Extend GitNotes._load() with a local objname -> note cache."""
|
||||
if objname not in self._cache:
|
||||
self._cache[objname] = GitNotes._load(self, objname)
|
||||
return self._cache[objname]
|
||||
|
||||
def import_note (self, objname, data, gfi):
|
||||
"""Extend GitNotes.import_note() with a local objname -> note cache."""
|
||||
if not data.endswith("\n"):
|
||||
data += "\n"
|
||||
assert objname not in self._cache
|
||||
self._cache[objname] = data
|
||||
GitNotes.import_note(self, objname, data, gfi)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
17
git_remote_helpers/setup.py
Normal file
17
git_remote_helpers/setup.py
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Distutils build/install script for the git_remote_helpers package."""
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(
|
||||
name = 'git_remote_helpers',
|
||||
version = '0.1.0',
|
||||
description = 'Git remote helper program for non-git repositories',
|
||||
license = 'GPLv2',
|
||||
author = 'The Git Community',
|
||||
author_email = 'git@vger.kernel.org',
|
||||
url = 'http://www.git-scm.com/',
|
||||
package_dir = {'git_remote_helpers': ''},
|
||||
packages = ['git_remote_helpers', 'git_remote_helpers.git'],
|
||||
)
|
||||
194
git_remote_helpers/util.py
Normal file
194
git_remote_helpers/util.py
Normal file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Misc. useful functionality used by the rest of this package.
|
||||
|
||||
This module provides common functionality used by the other modules in
|
||||
this package.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
# Whether or not to show debug messages
|
||||
DEBUG = False
|
||||
|
||||
def notify(msg, *args):
|
||||
"""Print a message to stderr."""
|
||||
print >> sys.stderr, msg % args
|
||||
|
||||
def debug (msg, *args):
|
||||
"""Print a debug message to stderr when DEBUG is enabled."""
|
||||
if DEBUG:
|
||||
print >> sys.stderr, msg % args
|
||||
|
||||
def error (msg, *args):
|
||||
"""Print an error message to stderr."""
|
||||
print >> sys.stderr, "ERROR:", msg % args
|
||||
|
||||
def warn(msg, *args):
|
||||
"""Print a warning message to stderr."""
|
||||
print >> sys.stderr, "warning:", msg % args
|
||||
|
||||
def die (msg, *args):
|
||||
"""Print as error message to stderr and exit the program."""
|
||||
error(msg, *args)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class ProgressIndicator(object):
|
||||
|
||||
"""Simple progress indicator.
|
||||
|
||||
Displayed as a spinning character by default, but can be customized
|
||||
by passing custom messages that overrides the spinning character.
|
||||
|
||||
"""
|
||||
|
||||
States = ("|", "/", "-", "\\")
|
||||
|
||||
def __init__ (self, prefix = "", f = sys.stdout):
|
||||
"""Create a new ProgressIndicator, bound to the given file object."""
|
||||
self.n = 0 # Simple progress counter
|
||||
self.f = f # Progress is written to this file object
|
||||
self.prev_len = 0 # Length of previous msg (to be overwritten)
|
||||
self.prefix = prefix # Prefix prepended to each progress message
|
||||
self.prefix_lens = [] # Stack of prefix string lengths
|
||||
|
||||
def pushprefix (self, prefix):
|
||||
"""Append the given prefix onto the prefix stack."""
|
||||
self.prefix_lens.append(len(self.prefix))
|
||||
self.prefix += prefix
|
||||
|
||||
def popprefix (self):
|
||||
"""Remove the last prefix from the prefix stack."""
|
||||
prev_len = self.prefix_lens.pop()
|
||||
self.prefix = self.prefix[:prev_len]
|
||||
|
||||
def __call__ (self, msg = None, lf = False):
|
||||
"""Indicate progress, possibly with a custom message."""
|
||||
if msg is None:
|
||||
msg = self.States[self.n % len(self.States)]
|
||||
msg = self.prefix + msg
|
||||
print >> self.f, "\r%-*s" % (self.prev_len, msg),
|
||||
self.prev_len = len(msg.expandtabs())
|
||||
if lf:
|
||||
print >> self.f
|
||||
self.prev_len = 0
|
||||
self.n += 1
|
||||
|
||||
def finish (self, msg = "done", noprefix = False):
|
||||
"""Finalize progress indication with the given message."""
|
||||
if noprefix:
|
||||
self.prefix = ""
|
||||
self(msg, True)
|
||||
|
||||
|
||||
def start_command (args, cwd = None, shell = False, add_env = None,
|
||||
stdin = subprocess.PIPE, stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE):
|
||||
"""Start the given command, and return a subprocess object.
|
||||
|
||||
This provides a simpler interface to the subprocess module.
|
||||
|
||||
"""
|
||||
env = None
|
||||
if add_env is not None:
|
||||
env = os.environ.copy()
|
||||
env.update(add_env)
|
||||
return subprocess.Popen(args, bufsize = 1, stdin = stdin, stdout = stdout,
|
||||
stderr = stderr, cwd = cwd, shell = shell,
|
||||
env = env, universal_newlines = True)
|
||||
|
||||
|
||||
def run_command (args, cwd = None, shell = False, add_env = None,
|
||||
flag_error = True):
|
||||
"""Run the given command to completion, and return its results.
|
||||
|
||||
This provides a simpler interface to the subprocess module.
|
||||
|
||||
The results are formatted as a 3-tuple: (exit_code, output, errors)
|
||||
|
||||
If flag_error is enabled, Error messages will be produced if the
|
||||
subprocess terminated with a non-zero exit code and/or stderr
|
||||
output.
|
||||
|
||||
The other arguments are passed on to start_command().
|
||||
|
||||
"""
|
||||
process = start_command(args, cwd, shell, add_env)
|
||||
(output, errors) = process.communicate()
|
||||
exit_code = process.returncode
|
||||
if flag_error and errors:
|
||||
error("'%s' returned errors:\n---\n%s---", " ".join(args), errors)
|
||||
if flag_error and exit_code:
|
||||
error("'%s' returned exit code %i", " ".join(args), exit_code)
|
||||
return (exit_code, output, errors)
|
||||
|
||||
|
||||
def file_reader_method (missing_ok = False):
|
||||
"""Decorator for simplifying reading of files.
|
||||
|
||||
If missing_ok is True, a failure to open a file for reading will
|
||||
not raise the usual IOError, but instead the wrapped method will be
|
||||
called with f == None. The method must in this case properly
|
||||
handle f == None.
|
||||
|
||||
"""
|
||||
def _wrap (method):
|
||||
"""Teach given method to handle both filenames and file objects.
|
||||
|
||||
The given method must take a file object as its second argument
|
||||
(the first argument being 'self', of course). This decorator
|
||||
will take a filename given as the second argument and promote
|
||||
it to a file object.
|
||||
|
||||
"""
|
||||
def _wrapped_method (self, filename, *args, **kwargs):
|
||||
if isinstance(filename, file):
|
||||
f = filename
|
||||
else:
|
||||
try:
|
||||
f = open(filename, 'r')
|
||||
except IOError:
|
||||
if missing_ok:
|
||||
f = None
|
||||
else:
|
||||
raise
|
||||
try:
|
||||
return method(self, f, *args, **kwargs)
|
||||
finally:
|
||||
if not isinstance(filename, file) and f:
|
||||
f.close()
|
||||
return _wrapped_method
|
||||
return _wrap
|
||||
|
||||
|
||||
def file_writer_method (method):
|
||||
"""Decorator for simplifying writing of files.
|
||||
|
||||
Enables the given method to handle both filenames and file objects.
|
||||
|
||||
The given method must take a file object as its second argument
|
||||
(the first argument being 'self', of course). This decorator will
|
||||
take a filename given as the second argument and promote it to a
|
||||
file object.
|
||||
|
||||
"""
|
||||
def _new_method (self, filename, *args, **kwargs):
|
||||
if isinstance(filename, file):
|
||||
f = filename
|
||||
else:
|
||||
# Make sure the containing directory exists
|
||||
parent_dir = os.path.dirname(filename)
|
||||
if not os.path.isdir(parent_dir):
|
||||
os.makedirs(parent_dir)
|
||||
f = open(filename, 'w')
|
||||
try:
|
||||
return method(self, f, *args, **kwargs)
|
||||
finally:
|
||||
if not isinstance(filename, file):
|
||||
f.close()
|
||||
return _new_method
|
||||
28
http.c
28
http.c
@@ -7,6 +7,12 @@ int active_requests;
|
||||
int http_is_verbose;
|
||||
size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x070a06
|
||||
#define LIBCURL_CAN_HANDLE_AUTH_ANY
|
||||
#endif
|
||||
|
||||
static int min_curl_sessions = 1;
|
||||
static int curl_session_count;
|
||||
#ifdef USE_CURL_MULTI
|
||||
static int max_requests = -1;
|
||||
static CURLM *curlm;
|
||||
@@ -152,6 +158,14 @@ static int http_options(const char *var, const char *value, void *cb)
|
||||
ssl_cert_password_required = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("http.minsessions", var)) {
|
||||
min_curl_sessions = git_config_int(var, value);
|
||||
#ifndef USE_CURL_MULTI
|
||||
if (min_curl_sessions > 1)
|
||||
min_curl_sessions = 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#ifdef USE_CURL_MULTI
|
||||
if (!strcmp("http.maxrequests", var)) {
|
||||
max_requests = git_config_int(var, value);
|
||||
@@ -230,6 +244,9 @@ static CURL *get_curl_handle(void)
|
||||
#if LIBCURL_VERSION_NUM >= 0x070907
|
||||
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
|
||||
#endif
|
||||
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
|
||||
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
||||
#endif
|
||||
|
||||
init_curl_http_auth(result);
|
||||
|
||||
@@ -372,6 +389,7 @@ void http_init(struct remote *remote)
|
||||
if (curl_ssl_verify == -1)
|
||||
curl_ssl_verify = 1;
|
||||
|
||||
curl_session_count = 0;
|
||||
#ifdef USE_CURL_MULTI
|
||||
if (max_requests < 1)
|
||||
max_requests = DEFAULT_MAX_REQUESTS;
|
||||
@@ -480,6 +498,7 @@ struct active_request_slot *get_active_slot(void)
|
||||
#else
|
||||
slot->curl = curl_easy_duphandle(curl_default);
|
||||
#endif
|
||||
curl_session_count++;
|
||||
}
|
||||
|
||||
active_requests++;
|
||||
@@ -558,9 +577,11 @@ void fill_active_slots(void)
|
||||
}
|
||||
|
||||
while (slot != NULL) {
|
||||
if (!slot->in_use && slot->curl != NULL) {
|
||||
if (!slot->in_use && slot->curl != NULL
|
||||
&& curl_session_count > min_curl_sessions) {
|
||||
curl_easy_cleanup(slot->curl);
|
||||
slot->curl = NULL;
|
||||
curl_session_count--;
|
||||
}
|
||||
slot = slot->next;
|
||||
}
|
||||
@@ -633,12 +654,13 @@ static void closedown_active_slot(struct active_request_slot *slot)
|
||||
void release_active_slot(struct active_request_slot *slot)
|
||||
{
|
||||
closedown_active_slot(slot);
|
||||
if (slot->curl) {
|
||||
if (slot->curl && curl_session_count > min_curl_sessions) {
|
||||
#ifdef USE_CURL_MULTI
|
||||
curl_multi_remove_handle(curlm, slot->curl);
|
||||
#endif
|
||||
curl_easy_cleanup(slot->curl);
|
||||
slot->curl = NULL;
|
||||
curl_session_count--;
|
||||
}
|
||||
#ifdef USE_CURL_MULTI
|
||||
fill_active_slots();
|
||||
@@ -1244,7 +1266,7 @@ int finish_http_object_request(struct http_object_request *freq)
|
||||
process_http_object_request(freq);
|
||||
|
||||
if (freq->http_code == 416) {
|
||||
fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
|
||||
warning("requested range invalid; we may already have all the data.");
|
||||
} else if (freq->curl_result != CURLE_OK) {
|
||||
if (stat(freq->tmpfile, &st) == 0)
|
||||
if (st.st_size == 0)
|
||||
|
||||
@@ -1322,7 +1322,7 @@ int read_index_from(struct index_state *istate, const char *path)
|
||||
* extension name (4-byte) and section length
|
||||
* in 4-byte network byte order.
|
||||
*/
|
||||
unsigned long extsize;
|
||||
uint32_t extsize;
|
||||
memcpy(&extsize, (char *)mmap + src_offset + 4, 4);
|
||||
extsize = ntohl(extsize);
|
||||
if (read_index_extension(istate,
|
||||
|
||||
@@ -290,6 +290,7 @@ struct rpc_state {
|
||||
int out;
|
||||
struct strbuf result;
|
||||
unsigned gzip_request : 1;
|
||||
unsigned initial_buffer : 1;
|
||||
};
|
||||
|
||||
static size_t rpc_out(void *ptr, size_t eltsize,
|
||||
@@ -300,6 +301,7 @@ static size_t rpc_out(void *ptr, size_t eltsize,
|
||||
size_t avail = rpc->len - rpc->pos;
|
||||
|
||||
if (!avail) {
|
||||
rpc->initial_buffer = 0;
|
||||
avail = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
|
||||
if (!avail)
|
||||
return 0;
|
||||
@@ -314,6 +316,29 @@ static size_t rpc_out(void *ptr, size_t eltsize,
|
||||
return avail;
|
||||
}
|
||||
|
||||
#ifndef NO_CURL_IOCTL
|
||||
curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
|
||||
{
|
||||
struct rpc_state *rpc = clientp;
|
||||
|
||||
switch (cmd) {
|
||||
case CURLIOCMD_NOP:
|
||||
return CURLIOE_OK;
|
||||
|
||||
case CURLIOCMD_RESTARTREAD:
|
||||
if (rpc->initial_buffer) {
|
||||
rpc->pos = 0;
|
||||
return CURLIOE_OK;
|
||||
}
|
||||
fprintf(stderr, "Unable to rewind rpc post data - try increasing http.postBuffer\n");
|
||||
return CURLIOE_FAILRESTART;
|
||||
|
||||
default:
|
||||
return CURLIOE_UNKNOWNCMD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t rpc_in(const void *ptr, size_t eltsize,
|
||||
size_t nmemb, void *buffer_)
|
||||
{
|
||||
@@ -370,8 +395,13 @@ static int post_rpc(struct rpc_state *rpc)
|
||||
*/
|
||||
headers = curl_slist_append(headers, "Expect: 100-continue");
|
||||
headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
|
||||
rpc->initial_buffer = 1;
|
||||
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
|
||||
#ifndef NO_CURL_IOCTL
|
||||
curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, rpc_ioctl);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, rpc);
|
||||
#endif
|
||||
if (options.verbosity > 1) {
|
||||
fprintf(stderr, "POST %s (chunked)\n", rpc->service_name);
|
||||
fflush(stderr);
|
||||
|
||||
42
remote.c
42
remote.c
@@ -53,6 +53,11 @@ static struct rewrites rewrites_push;
|
||||
#define BUF_SIZE (2048)
|
||||
static char buffer[BUF_SIZE];
|
||||
|
||||
static int valid_remote(const struct remote *remote)
|
||||
{
|
||||
return (!!remote->url) || (!!remote->foreign_vcs);
|
||||
}
|
||||
|
||||
static const char *alias_url(const char *url, struct rewrites *r)
|
||||
{
|
||||
int i, j;
|
||||
@@ -441,6 +446,8 @@ static int handle_config(const char *key, const char *value, void *cb)
|
||||
} else if (!strcmp(subkey, ".proxy")) {
|
||||
return git_config_string((const char **)&remote->http_proxy,
|
||||
key, value);
|
||||
} else if (!strcmp(subkey, ".vcs")) {
|
||||
return git_config_string(&remote->foreign_vcs, key, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -668,6 +675,16 @@ static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
|
||||
return parse_refspec_internal(nr_refspec, refspec, 0, 0);
|
||||
}
|
||||
|
||||
void free_refspec(int nr_refspec, struct refspec *refspec)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nr_refspec; i++) {
|
||||
free(refspec[i].src);
|
||||
free(refspec[i].dst);
|
||||
}
|
||||
free(refspec);
|
||||
}
|
||||
|
||||
static int valid_remote_nick(const char *name)
|
||||
{
|
||||
if (!name[0] || is_dot_or_dotdot(name))
|
||||
@@ -690,14 +707,14 @@ struct remote *remote_get(const char *name)
|
||||
|
||||
ret = make_remote(name, 0);
|
||||
if (valid_remote_nick(name)) {
|
||||
if (!ret->url)
|
||||
if (!valid_remote(ret))
|
||||
read_remotes_file(ret);
|
||||
if (!ret->url)
|
||||
if (!valid_remote(ret))
|
||||
read_branches_file(ret);
|
||||
}
|
||||
if (name_given && !ret->url)
|
||||
if (name_given && !valid_remote(ret))
|
||||
add_url_alias(ret, name);
|
||||
if (!ret->url)
|
||||
if (!valid_remote(ret))
|
||||
return NULL;
|
||||
ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);
|
||||
ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);
|
||||
@@ -810,6 +827,23 @@ static int match_name_with_pattern(const char *key, const char *name,
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
char *ret = NULL;
|
||||
for (i = 0; i < nr_refspec; i++) {
|
||||
struct refspec *refspec = refspecs + i;
|
||||
if (refspec->pattern) {
|
||||
if (match_name_with_pattern(refspec->src, name,
|
||||
refspec->dst, &ret))
|
||||
return ret;
|
||||
} else if (!strcmp(refspec->src, name))
|
||||
return strdup(refspec->dst);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int remote_find_tracking(struct remote *remote, struct refspec *refspec)
|
||||
{
|
||||
int find_src = refspec->src == NULL;
|
||||
|
||||
7
remote.h
7
remote.h
@@ -11,6 +11,8 @@ struct remote {
|
||||
const char *name;
|
||||
int origin;
|
||||
|
||||
const char *foreign_vcs;
|
||||
|
||||
const char **url;
|
||||
int url_nr;
|
||||
int url_alloc;
|
||||
@@ -89,6 +91,11 @@ void ref_remove_duplicates(struct ref *ref_map);
|
||||
int valid_fetch_refspec(const char *refspec);
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
|
||||
|
||||
void free_refspec(int nr_refspec, struct refspec *refspec);
|
||||
|
||||
char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
|
||||
const char *name);
|
||||
|
||||
int match_refs(struct ref *src, struct ref **dst,
|
||||
int nr_refspec, const char **refspec, int all);
|
||||
|
||||
|
||||
@@ -791,7 +791,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
|
||||
revs->ignore_merges = 1;
|
||||
revs->simplify_history = 1;
|
||||
DIFF_OPT_SET(&revs->pruning, RECURSIVE);
|
||||
DIFF_OPT_SET(&revs->pruning, QUIET);
|
||||
DIFF_OPT_SET(&revs->pruning, QUICK);
|
||||
revs->pruning.add_remove = file_add_remove;
|
||||
revs->pruning.change = file_change;
|
||||
revs->lifo = 1;
|
||||
|
||||
15
setup.c
15
setup.c
@@ -77,6 +77,18 @@ int check_filename(const char *prefix, const char *arg)
|
||||
die_errno("failed to stat '%s'", arg);
|
||||
}
|
||||
|
||||
static void NORETURN die_verify_filename(const char *prefix, const char *arg)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
unsigned mode;
|
||||
/* try a detailed diagnostic ... */
|
||||
get_sha1_with_mode_1(arg, sha1, &mode, 0, prefix);
|
||||
/* ... or fall back the most general message. */
|
||||
die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
|
||||
"Use '--' to separate paths from revisions", arg);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify a filename that we got as an argument for a pathspec
|
||||
* entry. Note that a filename that begins with "-" never verifies
|
||||
@@ -90,8 +102,7 @@ void verify_filename(const char *prefix, const char *arg)
|
||||
die("bad flag '%s' used after filename", arg);
|
||||
if (check_filename(prefix, arg))
|
||||
return;
|
||||
die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
|
||||
"Use '--' to separate paths from revisions", arg);
|
||||
die_verify_filename(prefix, arg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
115
sha1_name.c
115
sha1_name.c
@@ -804,7 +804,96 @@ int get_sha1(const char *name, unsigned char *sha1)
|
||||
return get_sha1_with_mode(name, sha1, &unused);
|
||||
}
|
||||
|
||||
int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
|
||||
/* Must be called only when object_name:filename doesn't exist. */
|
||||
static void diagnose_invalid_sha1_path(const char *prefix,
|
||||
const char *filename,
|
||||
const unsigned char *tree_sha1,
|
||||
const char *object_name)
|
||||
{
|
||||
struct stat st;
|
||||
unsigned char sha1[20];
|
||||
unsigned mode;
|
||||
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
|
||||
if (!lstat(filename, &st))
|
||||
die("Path '%s' exists on disk, but not in '%s'.",
|
||||
filename, object_name);
|
||||
if (errno == ENOENT || errno == ENOTDIR) {
|
||||
char *fullname = xmalloc(strlen(filename)
|
||||
+ strlen(prefix) + 1);
|
||||
strcpy(fullname, prefix);
|
||||
strcat(fullname, filename);
|
||||
|
||||
if (!get_tree_entry(tree_sha1, fullname,
|
||||
sha1, &mode)) {
|
||||
die("Path '%s' exists, but not '%s'.\n"
|
||||
"Did you mean '%s:%s'?",
|
||||
fullname,
|
||||
filename,
|
||||
object_name,
|
||||
fullname);
|
||||
}
|
||||
die("Path '%s' does not exist in '%s'",
|
||||
filename, object_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called only when :stage:filename doesn't exist. */
|
||||
static void diagnose_invalid_index_path(int stage,
|
||||
const char *prefix,
|
||||
const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
struct cache_entry *ce;
|
||||
int pos;
|
||||
unsigned namelen = strlen(filename);
|
||||
unsigned fullnamelen;
|
||||
char *fullname;
|
||||
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
|
||||
/* Wrong stage number? */
|
||||
pos = cache_name_pos(filename, namelen);
|
||||
if (pos < 0)
|
||||
pos = -pos - 1;
|
||||
ce = active_cache[pos];
|
||||
if (ce_namelen(ce) == namelen &&
|
||||
!memcmp(ce->name, filename, namelen))
|
||||
die("Path '%s' is in the index, but not at stage %d.\n"
|
||||
"Did you mean ':%d:%s'?",
|
||||
filename, stage,
|
||||
ce_stage(ce), filename);
|
||||
|
||||
/* Confusion between relative and absolute filenames? */
|
||||
fullnamelen = namelen + strlen(prefix);
|
||||
fullname = xmalloc(fullnamelen + 1);
|
||||
strcpy(fullname, prefix);
|
||||
strcat(fullname, filename);
|
||||
pos = cache_name_pos(fullname, fullnamelen);
|
||||
if (pos < 0)
|
||||
pos = -pos - 1;
|
||||
ce = active_cache[pos];
|
||||
if (ce_namelen(ce) == fullnamelen &&
|
||||
!memcmp(ce->name, fullname, fullnamelen))
|
||||
die("Path '%s' is in the index, but not '%s'.\n"
|
||||
"Did you mean ':%d:%s'?",
|
||||
fullname, filename,
|
||||
ce_stage(ce), fullname);
|
||||
|
||||
if (!lstat(filename, &st))
|
||||
die("Path '%s' exists on disk, but not in the index.", filename);
|
||||
if (errno == ENOENT || errno == ENOTDIR)
|
||||
die("Path '%s' does not exist (neither on disk nor in the index).",
|
||||
filename);
|
||||
|
||||
free(fullname);
|
||||
}
|
||||
|
||||
|
||||
int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int gently, const char *prefix)
|
||||
{
|
||||
int ret, bracket_depth;
|
||||
int namelen = strlen(name);
|
||||
@@ -850,6 +939,8 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (!gently)
|
||||
diagnose_invalid_index_path(stage, prefix, cp);
|
||||
return -1;
|
||||
}
|
||||
for (cp = name, bracket_depth = 0; *cp; cp++) {
|
||||
@@ -862,9 +953,25 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
|
||||
}
|
||||
if (*cp == ':') {
|
||||
unsigned char tree_sha1[20];
|
||||
if (!get_sha1_1(name, cp-name, tree_sha1))
|
||||
return get_tree_entry(tree_sha1, cp+1, sha1,
|
||||
mode);
|
||||
char *object_name = NULL;
|
||||
if (!gently) {
|
||||
object_name = xmalloc(cp-name+1);
|
||||
strncpy(object_name, name, cp-name);
|
||||
object_name[cp-name] = '\0';
|
||||
}
|
||||
if (!get_sha1_1(name, cp-name, tree_sha1)) {
|
||||
const char *filename = cp+1;
|
||||
ret = get_tree_entry(tree_sha1, filename, sha1, mode);
|
||||
if (!gently) {
|
||||
diagnose_invalid_sha1_path(prefix, filename,
|
||||
tree_sha1, object_name);
|
||||
free(object_name);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
if (!gently)
|
||||
die("Invalid object name '%s'.", object_name);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PATH_LIST_H
|
||||
#define PATH_LIST_H
|
||||
#ifndef STRING_LIST_H
|
||||
#define STRING_LIST_H
|
||||
|
||||
struct string_list_item {
|
||||
char *string;
|
||||
@@ -39,4 +39,4 @@ struct string_list_item *string_list_append(const char *string, struct string_li
|
||||
void sort_string_list(struct string_list *list);
|
||||
int unsorted_string_list_has_string(struct string_list *list, const char *string);
|
||||
|
||||
#endif /* PATH_LIST_H */
|
||||
#endif /* STRING_LIST_H */
|
||||
|
||||
9
t/README
9
t/README
@@ -75,6 +75,15 @@ appropriately before running "make".
|
||||
As the names depend on the tests' file names, it is safe to
|
||||
run the tests with this option in parallel.
|
||||
|
||||
--with-dashes::
|
||||
By default tests are run without dashed forms of
|
||||
commands (like git-commit) in the PATH (it only uses
|
||||
wrappers from ../bin-wrappers). Use this option to include
|
||||
the build directory (..) in the PATH, which contains all
|
||||
the dashed forms of commands. This option is currently
|
||||
implied by other options like --valgrind and
|
||||
GIT_TEST_INSTALLED.
|
||||
|
||||
You can also set the GIT_TEST_INSTALLED environment variable to
|
||||
the bindir of an existing git installation to test that installation.
|
||||
You still need to have built this git sandbox, from which various
|
||||
|
||||
@@ -259,7 +259,7 @@ test_expect_success 'git repack' 'git repack'
|
||||
test_expect_success 'git prune-packed' 'git prune-packed'
|
||||
test_expect_success '-> only packed objects' '
|
||||
git prune && # Remove conflict marked blobs
|
||||
! find .git/objects/[0-9a-f][0-9a-f] -type f
|
||||
test $(find .git/objects/[0-9a-f][0-9a-f] -type f -print 2>/dev/null | wc -l) = 0
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -683,6 +683,34 @@ test_expect_success 'set --bool-or-int' '
|
||||
|
||||
rm .git/config
|
||||
|
||||
cat >expect <<\EOF
|
||||
[path]
|
||||
home = ~/
|
||||
normal = /dev/null
|
||||
trailingtilde = foo~
|
||||
EOF
|
||||
|
||||
test_expect_success 'set --path' '
|
||||
git config --path path.home "~/" &&
|
||||
git config --path path.normal "/dev/null" &&
|
||||
git config --path path.trailingtilde "foo~" &&
|
||||
test_cmp expect .git/config'
|
||||
|
||||
cat >expect <<EOF
|
||||
$HOME/
|
||||
/dev/null
|
||||
foo~
|
||||
EOF
|
||||
|
||||
test_expect_success 'get --path' '
|
||||
git config --get --path path.home > result &&
|
||||
git config --get --path path.normal >> result &&
|
||||
git config --get --path path.trailingtilde >> result &&
|
||||
test_cmp expect result
|
||||
'
|
||||
|
||||
rm .git/config
|
||||
|
||||
git config quote.leading " test"
|
||||
git config quote.ending "test "
|
||||
git config quote.semicolon "test;test"
|
||||
|
||||
69
t/t1506-rev-parse-diagnosis.sh
Executable file
69
t/t1506-rev-parse-diagnosis.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='test git rev-parse diagnosis for invalid argument'
|
||||
|
||||
exec </dev/null
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
HASH_file=
|
||||
|
||||
test_expect_success 'set up basic repo' '
|
||||
echo one > file.txt &&
|
||||
mkdir subdir &&
|
||||
echo two > subdir/file.txt &&
|
||||
echo three > subdir/file2.txt &&
|
||||
git add . &&
|
||||
git commit -m init &&
|
||||
echo four > index-only.txt &&
|
||||
git add index-only.txt &&
|
||||
echo five > disk-only.txt
|
||||
'
|
||||
|
||||
test_expect_success 'correct file objects' '
|
||||
HASH_file=$(git rev-parse HEAD:file.txt) &&
|
||||
git rev-parse HEAD:subdir/file.txt &&
|
||||
git rev-parse :index-only.txt &&
|
||||
(cd subdir &&
|
||||
git rev-parse HEAD:subdir/file2.txt &&
|
||||
test $HASH_file = $(git rev-parse HEAD:file.txt) &&
|
||||
test $HASH_file = $(git rev-parse :file.txt) &&
|
||||
test $HASH_file = $(git rev-parse :0:file.txt) )
|
||||
'
|
||||
|
||||
test_expect_success 'incorrect revision id' '
|
||||
test_must_fail git rev-parse foobar:file.txt 2>error &&
|
||||
grep "Invalid object name '"'"'foobar'"'"'." error &&
|
||||
test_must_fail git rev-parse foobar 2> error &&
|
||||
grep "unknown revision or path not in the working tree." error
|
||||
'
|
||||
|
||||
test_expect_success 'incorrect file in sha1:path' '
|
||||
test_must_fail git rev-parse HEAD:nothing.txt 2> error &&
|
||||
grep "fatal: Path '"'"'nothing.txt'"'"' does not exist in '"'"'HEAD'"'"'" error &&
|
||||
test_must_fail git rev-parse HEAD:index-only.txt 2> error &&
|
||||
grep "fatal: Path '"'"'index-only.txt'"'"' exists on disk, but not in '"'"'HEAD'"'"'." error &&
|
||||
(cd subdir &&
|
||||
test_must_fail git rev-parse HEAD:file2.txt 2> error &&
|
||||
grep "Did you mean '"'"'HEAD:subdir/file2.txt'"'"'?" error )
|
||||
'
|
||||
|
||||
test_expect_success 'incorrect file in :path and :N:path' '
|
||||
test_must_fail git rev-parse :nothing.txt 2> error &&
|
||||
grep "fatal: Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." error &&
|
||||
test_must_fail git rev-parse :1:nothing.txt 2> error &&
|
||||
grep "Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." error &&
|
||||
test_must_fail git rev-parse :1:file.txt 2> error &&
|
||||
grep "Did you mean '"'"':0:file.txt'"'"'?" error &&
|
||||
(cd subdir &&
|
||||
test_must_fail git rev-parse :1:file.txt 2> error &&
|
||||
grep "Did you mean '"'"':0:file.txt'"'"'?" error &&
|
||||
test_must_fail git rev-parse :file2.txt 2> error &&
|
||||
grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error &&
|
||||
test_must_fail git rev-parse :2:file2.txt 2> error &&
|
||||
grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error) &&
|
||||
test_must_fail git rev-parse :disk-only.txt 2> error &&
|
||||
grep "fatal: Path '"'"'disk-only.txt'"'"' exists on disk, but not in the index." error
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -93,8 +93,6 @@ git diff > out
|
||||
test_expect_success 'another test, without options' 'test_cmp expect out'
|
||||
|
||||
cat << EOF > expect
|
||||
diff --git a/x b/x
|
||||
index d99af23..8b32fb5 100644
|
||||
EOF
|
||||
git diff -w > out
|
||||
test_expect_success 'another test, with -w' 'test_cmp expect out'
|
||||
@@ -386,6 +384,18 @@ test_expect_success 'checkdiff allows new blank lines' '
|
||||
git diff --check
|
||||
'
|
||||
|
||||
cat <<EOF >expect
|
||||
EOF
|
||||
test_expect_success 'whitespace-only changes not reported' '
|
||||
git reset --hard &&
|
||||
echo >x "hello world" &&
|
||||
git add x &&
|
||||
git commit -m "hello 1" &&
|
||||
echo >x "hello world" &&
|
||||
git diff -b >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'combined diff with autocrlf conversion' '
|
||||
|
||||
git reset --hard &&
|
||||
|
||||
@@ -20,11 +20,27 @@ test_expect_success setup '
|
||||
|
||||
blue_grep='7;34m' ;# ESC [ 7 ; 3 4 m
|
||||
|
||||
printf "\033[%s" "$blue_grep" >check-grep
|
||||
if (grep "$blue_grep" <check-grep | grep "$blue_grep") >/dev/null 2>&1
|
||||
then
|
||||
grep_a=grep
|
||||
elif (grep -a "$blue_grep" <check-grep | grep -a "$blue_grep") >/dev/null 2>&1
|
||||
then
|
||||
grep_a='grep -a'
|
||||
else
|
||||
grep_a=grep ;# expected to fail...
|
||||
fi
|
||||
rm -f check-grep
|
||||
|
||||
prepare_output () {
|
||||
git diff --color >output
|
||||
$grep_a "$blue_grep" output >error
|
||||
$grep_a -v "$blue_grep" output >normal
|
||||
}
|
||||
|
||||
test_expect_success default '
|
||||
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
@@ -37,9 +53,7 @@ test_expect_success default '
|
||||
test_expect_success 'without -trail' '
|
||||
|
||||
git config core.whitespace -trail
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
@@ -53,9 +67,7 @@ test_expect_success 'without -trail (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=-trail" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
@@ -69,9 +81,7 @@ test_expect_success 'without -space' '
|
||||
|
||||
rm -f .gitattributes
|
||||
git config core.whitespace -space
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
@@ -85,9 +95,7 @@ test_expect_success 'without -space (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=-space" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
@@ -101,9 +109,7 @@ test_expect_success 'with indent-non-tab only' '
|
||||
|
||||
rm -f .gitattributes
|
||||
git config core.whitespace indent,-trailing,-space
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight error >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
@@ -117,9 +123,7 @@ test_expect_success 'with indent-non-tab only (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=indent,-trailing,-space" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight error >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
@@ -133,9 +137,7 @@ test_expect_success 'with cr-at-eol' '
|
||||
|
||||
rm -f .gitattributes
|
||||
git config core.whitespace cr-at-eol
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
@@ -149,9 +151,7 @@ test_expect_success 'with cr-at-eol (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=trailing,cr-at-eol" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
prepare_output
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
@@ -195,7 +195,7 @@ test_expect_success 'color new trailing blank lines' '
|
||||
git add x &&
|
||||
{ echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x &&
|
||||
git diff --color x >output &&
|
||||
cnt=$(grep "${blue_grep}" output | wc -l) &&
|
||||
cnt=$($grep_a "${blue_grep}" output | wc -l) &&
|
||||
test $cnt = 2
|
||||
'
|
||||
|
||||
|
||||
@@ -12,19 +12,9 @@ test_expect_success setup '
|
||||
|
||||
'
|
||||
|
||||
decrypt_color () {
|
||||
sed \
|
||||
-e 's/.\[1m/<WHITE>/g' \
|
||||
-e 's/.\[31m/<RED>/g' \
|
||||
-e 's/.\[32m/<GREEN>/g' \
|
||||
-e 's/.\[35m/<MAGENTA>/g' \
|
||||
-e 's/.\[36m/<BROWN>/g' \
|
||||
-e 's/.\[m/<RESET>/g'
|
||||
}
|
||||
|
||||
word_diff () {
|
||||
test_must_fail git diff --no-index "$@" pre post > output &&
|
||||
decrypt_color < output > output.decrypted &&
|
||||
test_decode_color <output >output.decrypted &&
|
||||
test_cmp expect output.decrypted
|
||||
}
|
||||
|
||||
@@ -49,7 +39,7 @@ cat > expect <<\EOF
|
||||
<WHITE>index 330b04f..5ed8eff 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
<CYAN>@@ -1,3 +1,7 @@<RESET>
|
||||
<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
|
||||
|
||||
a = b + c<RESET>
|
||||
@@ -70,9 +60,9 @@ cat > expect <<\EOF
|
||||
<WHITE>index 330b04f..5ed8eff 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1 +1 @@<RESET>
|
||||
<CYAN>@@ -1 +1 @@<RESET>
|
||||
<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
|
||||
<BROWN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
|
||||
<CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
|
||||
|
||||
<GREEN>aa = a<RESET>
|
||||
|
||||
@@ -90,7 +80,7 @@ cat > expect <<\EOF
|
||||
<WHITE>index 330b04f..5ed8eff 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
<CYAN>@@ -1,3 +1,7 @@<RESET>
|
||||
h(4),<GREEN>hh<RESET>[44]
|
||||
|
||||
a = b + c<RESET>
|
||||
@@ -126,7 +116,7 @@ cat > expect <<\EOF
|
||||
<WHITE>index 330b04f..5ed8eff 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
<CYAN>@@ -1,3 +1,7 @@<RESET>
|
||||
h(4)<GREEN>,hh[44]<RESET>
|
||||
|
||||
a = b + c<RESET>
|
||||
@@ -168,7 +158,7 @@ cat > expect <<\EOF
|
||||
<WHITE>index 330b04f..5ed8eff 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
<CYAN>@@ -1,3 +1,7 @@<RESET>
|
||||
h(4),<GREEN>hh[44<RESET>]
|
||||
|
||||
a = b + c<RESET>
|
||||
@@ -190,7 +180,7 @@ cat > expect <<\EOF
|
||||
<WHITE>index c29453b..be22f37 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1 +1 @@<RESET>
|
||||
<CYAN>@@ -1 +1 @@<RESET>
|
||||
aaa (aaa) <GREEN>aaa<RESET>
|
||||
EOF
|
||||
|
||||
@@ -209,7 +199,7 @@ cat > expect <<\EOF
|
||||
<WHITE>index 289cb9d..2d06f37 100644<RESET>
|
||||
<WHITE>--- a/pre<RESET>
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1 +1 @@<RESET>
|
||||
<CYAN>@@ -1 +1 @@<RESET>
|
||||
(<RED>:<RESET>
|
||||
EOF
|
||||
|
||||
|
||||
63
t/t4040-whitespace-status.sh
Executable file
63
t/t4040-whitespace-status.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='diff --exit-code with whitespace'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
mkdir a b &&
|
||||
echo >c &&
|
||||
echo >a/d &&
|
||||
echo >b/e &&
|
||||
git add . &&
|
||||
test_tick &&
|
||||
git commit -m initial &&
|
||||
echo " " >a/d &&
|
||||
test_tick &&
|
||||
git commit -a -m second &&
|
||||
echo " " >a/d &&
|
||||
echo " " >b/e &&
|
||||
git add a/d
|
||||
'
|
||||
|
||||
test_expect_success 'diff-tree --exit-code' '
|
||||
test_must_fail git diff --exit-code HEAD^ HEAD &&
|
||||
test_must_fail git diff-tree --exit-code HEAD^ HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'diff-tree -b --exit-code' '
|
||||
git diff -b --exit-code HEAD^ HEAD &&
|
||||
git diff-tree -b -p --exit-code HEAD^ HEAD &&
|
||||
git diff-tree -b --exit-code HEAD^ HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'diff-index --cached --exit-code' '
|
||||
test_must_fail git diff --cached --exit-code HEAD &&
|
||||
test_must_fail git diff-index --cached --exit-code HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'diff-index -b -p --cached --exit-code' '
|
||||
git diff -b --cached --exit-code HEAD &&
|
||||
git diff-index -b -p --cached --exit-code HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'diff-index --exit-code' '
|
||||
test_must_fail git diff --exit-code HEAD &&
|
||||
test_must_fail git diff-index --exit-code HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'diff-index -b -p --exit-code' '
|
||||
git diff -b --exit-code HEAD &&
|
||||
git diff-index -b -p --exit-code HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'diff-files --exit-code' '
|
||||
test_must_fail git diff --exit-code &&
|
||||
test_must_fail git diff-files --exit-code
|
||||
'
|
||||
|
||||
test_expect_success 'diff-files -b -p --exit-code' '
|
||||
git diff -b --exit-code &&
|
||||
git diff-files -b -p --exit-code
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -32,7 +32,7 @@ test_expect_success setup '
|
||||
done &&
|
||||
git update-ref HEAD "$commit" &&
|
||||
git clone ./. victim &&
|
||||
( cd victim && git log ) &&
|
||||
( cd victim && git config receive.denyCurrentBranch warn && git log ) &&
|
||||
git update-ref HEAD "$zero" &&
|
||||
parent=$zero &&
|
||||
i=0 &&
|
||||
@@ -129,6 +129,7 @@ rewound_push_setup() {
|
||||
cd parent &&
|
||||
git init &&
|
||||
echo one >file && git add file && git commit -m one &&
|
||||
git config receive.denyCurrentBranch warn &&
|
||||
echo two >file && git commit -a -m two
|
||||
) &&
|
||||
git clone parent child &&
|
||||
@@ -190,16 +191,11 @@ test_expect_success 'pushing wildcard refspecs respects forcing' '
|
||||
test "$parent_head" = "$child_head"
|
||||
'
|
||||
|
||||
test_expect_success 'warn pushing to delete current branch' '
|
||||
test_expect_success 'deny pushing to delete current branch' '
|
||||
rewound_push_setup &&
|
||||
(
|
||||
cd child &&
|
||||
git send-pack ../parent :refs/heads/master 2>errs
|
||||
) &&
|
||||
grep "warning: to refuse deleting" child/errs &&
|
||||
(
|
||||
cd parent &&
|
||||
test_must_fail git rev-parse --verify master
|
||||
test_must_fail git send-pack ../parent :refs/heads/master 2>errs
|
||||
)
|
||||
'
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ test_expect_success setup '
|
||||
git update-ref refs/heads/master $commit0 &&
|
||||
git update-ref refs/heads/tofail $commit1 &&
|
||||
git clone ./. victim &&
|
||||
GIT_DIR=victim/.git git config receive.denyCurrentBranch warn &&
|
||||
GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 &&
|
||||
git update-ref refs/heads/master $commit1 &&
|
||||
git update-ref refs/heads/tofail $commit0
|
||||
|
||||
@@ -7,19 +7,19 @@ test_description='Test the post-checkout hook.'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
echo Data for commit0. >a &&
|
||||
echo Data for commit0. >b &&
|
||||
git update-index --add a &&
|
||||
git update-index --add b &&
|
||||
tree0=$(git write-tree) &&
|
||||
commit0=$(echo setup | git commit-tree $tree0) &&
|
||||
git update-ref refs/heads/master $commit0 &&
|
||||
git clone ./. clone1 &&
|
||||
git clone ./. clone2 &&
|
||||
GIT_DIR=clone2/.git git branch -a new2 &&
|
||||
echo Data for commit1. >clone2/b &&
|
||||
GIT_DIR=clone2/.git git add clone2/b &&
|
||||
GIT_DIR=clone2/.git git commit -m new2
|
||||
echo Data for commit0. >a &&
|
||||
echo Data for commit0. >b &&
|
||||
git update-index --add a &&
|
||||
git update-index --add b &&
|
||||
tree0=$(git write-tree) &&
|
||||
commit0=$(echo setup | git commit-tree $tree0) &&
|
||||
git update-ref refs/heads/master $commit0 &&
|
||||
git clone ./. clone1 &&
|
||||
git clone ./. clone2 &&
|
||||
GIT_DIR=clone2/.git git branch new2 &&
|
||||
echo Data for commit1. >clone2/b &&
|
||||
GIT_DIR=clone2/.git git add clone2/b &&
|
||||
GIT_DIR=clone2/.git git commit -m new2
|
||||
'
|
||||
|
||||
for clone in 1 2; do
|
||||
|
||||
@@ -8,6 +8,7 @@ test_expect_success setup '
|
||||
|
||||
>file1 && git add file1 && test_tick &&
|
||||
git commit -m Initial &&
|
||||
git config receive.denyCurrentBranch warn &&
|
||||
|
||||
mkdir another && (
|
||||
cd another &&
|
||||
|
||||
@@ -419,6 +419,20 @@ test_expect_success 'update default (overridden, with funny whitespace)' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'update (with remotes.default defined)' '
|
||||
|
||||
(cd one &&
|
||||
for b in $(git branch -r)
|
||||
do
|
||||
git branch -r -d $b || break
|
||||
done &&
|
||||
git config remotes.default "drosophila" &&
|
||||
git remote update &&
|
||||
git branch -r > output &&
|
||||
test_cmp expect output)
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '"remote show" does not show symbolic refs' '
|
||||
|
||||
git clone one three &&
|
||||
|
||||
@@ -12,6 +12,7 @@ mk_empty () {
|
||||
(
|
||||
cd testrepo &&
|
||||
git init &&
|
||||
git config receive.denyCurrentBranch warn &&
|
||||
mv .git/hooks .git/hooks-disabled
|
||||
)
|
||||
}
|
||||
@@ -546,6 +547,32 @@ test_expect_success 'allow deleting an invalid remote ref' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'allow deleting a ref using --delete' '
|
||||
mk_test heads/master &&
|
||||
(cd testrepo && git config receive.denyDeleteCurrent warn) &&
|
||||
git push testrepo --delete master &&
|
||||
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
|
||||
'
|
||||
|
||||
test_expect_success 'allow deleting a tag using --delete' '
|
||||
mk_test heads/master &&
|
||||
git tag -a -m dummy_message deltag heads/master &&
|
||||
git push testrepo --tags &&
|
||||
(cd testrepo && git rev-parse --verify -q refs/tags/deltag) &&
|
||||
git push testrepo --delete tag deltag &&
|
||||
(cd testrepo && test_must_fail git rev-parse --verify refs/tags/deltag)
|
||||
'
|
||||
|
||||
test_expect_success 'push --delete without args aborts' '
|
||||
mk_test heads/master &&
|
||||
test_must_fail git push testrepo --delete
|
||||
'
|
||||
|
||||
test_expect_success 'push --delete refuses src:dest refspecs' '
|
||||
mk_test heads/master &&
|
||||
test_must_fail git push testrepo --delete master:foo
|
||||
'
|
||||
|
||||
test_expect_success 'warn on push to HEAD of non-bare repository' '
|
||||
mk_test heads/master
|
||||
(cd testrepo &&
|
||||
|
||||
@@ -19,7 +19,8 @@ mk_repo_pair () {
|
||||
mkdir mirror &&
|
||||
(
|
||||
cd mirror &&
|
||||
git init
|
||||
git init &&
|
||||
git config receive.denyCurrentBranch warn
|
||||
) &&
|
||||
mkdir master &&
|
||||
(
|
||||
|
||||
@@ -20,13 +20,19 @@ fi
|
||||
#
|
||||
# The working directory is subdir-link.
|
||||
|
||||
mkdir subdir
|
||||
echo file >subdir/file
|
||||
git add subdir/file
|
||||
git commit -q -m file
|
||||
git clone -q . clone-repo
|
||||
ln -s clone-repo/subdir/ subdir-link
|
||||
|
||||
test_expect_success setup '
|
||||
mkdir subdir &&
|
||||
echo file >subdir/file &&
|
||||
git add subdir/file &&
|
||||
git commit -q -m file &&
|
||||
git clone -q . clone-repo &&
|
||||
ln -s clone-repo/subdir/ subdir-link &&
|
||||
(
|
||||
cd clone-repo &&
|
||||
git config receive.denyCurrentBranch warn
|
||||
) &&
|
||||
git config receive.denyCurrentBranch warn
|
||||
'
|
||||
|
||||
# Demonstrate that things work if we just avoid the symlink
|
||||
#
|
||||
|
||||
@@ -119,7 +119,9 @@ test_expect_success 'bundle clone with nonexistent HEAD' '
|
||||
test_expect_success 'clone empty repository' '
|
||||
cd "$D" &&
|
||||
mkdir empty &&
|
||||
(cd empty && git init) &&
|
||||
(cd empty &&
|
||||
git init &&
|
||||
git config receive.denyCurrentBranch warn) &&
|
||||
git clone empty empty-clone &&
|
||||
test_tick &&
|
||||
(cd empty-clone
|
||||
|
||||
@@ -423,7 +423,7 @@ test_expect_success 'skipped merge base when good and bad are siblings' '
|
||||
grep "merge base must be tested" my_bisect_log.txt &&
|
||||
grep $HASH4 my_bisect_log.txt &&
|
||||
git bisect skip > my_bisect_log.txt 2>&1 &&
|
||||
grep "Warning" my_bisect_log.txt &&
|
||||
grep "warning" my_bisect_log.txt &&
|
||||
grep $SIDE_HASH6 my_bisect_log.txt &&
|
||||
git bisect reset
|
||||
'
|
||||
|
||||
@@ -69,7 +69,7 @@ test_expect_success 'status' '
|
||||
cd test &&
|
||||
git checkout b1 >/dev/null &&
|
||||
# reports nothing to commit
|
||||
test_must_fail git status
|
||||
test_must_fail git commit --dry-run
|
||||
) >actual &&
|
||||
grep "have 1 and 1 different" actual
|
||||
'
|
||||
|
||||
@@ -31,8 +31,7 @@ test_expect_success 'Report new path with conflict' '
|
||||
cat >expect <<EOF
|
||||
# On branch side
|
||||
# Unmerged paths:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
# (use "git add <file>..." to mark resolution)
|
||||
# (use "git add/rm <file>..." as appropriate to mark resolution)
|
||||
#
|
||||
# deleted by us: foo
|
||||
#
|
||||
@@ -50,9 +49,11 @@ test_expect_success 'M/D conflict does not segfault' '
|
||||
git rm foo &&
|
||||
git commit -m delete &&
|
||||
test_must_fail git merge master &&
|
||||
test_must_fail git status > ../actual
|
||||
) &&
|
||||
test_cmp expect actual
|
||||
test_must_fail git commit --dry-run >../actual &&
|
||||
test_cmp ../expect ../actual &&
|
||||
git status >../actual &&
|
||||
test_cmp ../expect ../actual
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -139,19 +139,19 @@ test_expect_success \
|
||||
test_expect_success \
|
||||
'resetting to HEAD with no changes should succeed and do nothing' '
|
||||
git reset --hard &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset --hard HEAD &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset --soft &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset --soft HEAD &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset --mixed &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset --mixed HEAD &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc &&
|
||||
git reset HEAD &&
|
||||
check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
|
||||
'
|
||||
|
||||
@@ -29,6 +29,12 @@ test_expect_success 'soft reset is ok' '
|
||||
(cd .git && git reset --soft)
|
||||
'
|
||||
|
||||
test_expect_success 'hard reset works with GIT_WORK_TREE' '
|
||||
mkdir worktree &&
|
||||
GIT_WORK_TREE=$PWD/worktree GIT_DIR=$PWD/.git git reset --hard &&
|
||||
test_cmp file worktree/file
|
||||
'
|
||||
|
||||
test_expect_success 'setup bare' '
|
||||
git clone --bare . bare.git &&
|
||||
cd bare.git
|
||||
|
||||
@@ -211,6 +211,21 @@ test_expect_success 'amend commit to fix author' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'amend commit to fix date' '
|
||||
|
||||
test_tick &&
|
||||
newtick=$GIT_AUTHOR_DATE &&
|
||||
git reset --hard &&
|
||||
git cat-file -p HEAD |
|
||||
sed -e "s/author.*/author $author $newtick/" \
|
||||
-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" > \
|
||||
expected &&
|
||||
git commit --amend --date="$newtick" &&
|
||||
git cat-file -p HEAD > current &&
|
||||
test_cmp expected current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'sign off (1)' '
|
||||
|
||||
echo 1 >positive &&
|
||||
|
||||
@@ -19,8 +19,8 @@ test_expect_success 'status clean' '
|
||||
git status |
|
||||
grep "nothing to commit"
|
||||
'
|
||||
test_expect_success 'status -a clean' '
|
||||
git status -a |
|
||||
test_expect_success 'commit --dry-run -a clean' '
|
||||
git commit --dry-run -a |
|
||||
grep "nothing to commit"
|
||||
'
|
||||
test_expect_success 'rm submodule contents' '
|
||||
@@ -31,7 +31,7 @@ test_expect_success 'status clean (empty submodule dir)' '
|
||||
grep "nothing to commit"
|
||||
'
|
||||
test_expect_success 'status -a clean (empty submodule dir)' '
|
||||
git status -a |
|
||||
git commit --dry-run -a |
|
||||
grep "nothing to commit"
|
||||
'
|
||||
|
||||
|
||||
@@ -12,26 +12,26 @@ esac
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
: > tracked &&
|
||||
: > modified &&
|
||||
: >tracked &&
|
||||
: >modified &&
|
||||
mkdir dir1 &&
|
||||
: > dir1/tracked &&
|
||||
: > dir1/modified &&
|
||||
: >dir1/tracked &&
|
||||
: >dir1/modified &&
|
||||
mkdir dir2 &&
|
||||
: > dir1/tracked &&
|
||||
: > dir1/modified &&
|
||||
: >dir1/tracked &&
|
||||
: >dir1/modified &&
|
||||
git add . &&
|
||||
|
||||
git status >output &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m initial &&
|
||||
: > untracked &&
|
||||
: > dir1/untracked &&
|
||||
: > dir2/untracked &&
|
||||
echo 1 > dir1/modified &&
|
||||
echo 2 > dir2/modified &&
|
||||
echo 3 > dir2/added &&
|
||||
: >untracked &&
|
||||
: >dir1/untracked &&
|
||||
: >dir2/untracked &&
|
||||
echo 1 >dir1/modified &&
|
||||
echo 2 >dir2/modified &&
|
||||
echo 3 >dir2/added &&
|
||||
git add dir2/added
|
||||
'
|
||||
|
||||
@@ -41,7 +41,7 @@ test_expect_success 'status (1)' '
|
||||
|
||||
'
|
||||
|
||||
cat > expect << \EOF
|
||||
cat >expect <<\EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
@@ -67,7 +67,25 @@ EOF
|
||||
|
||||
test_expect_success 'status (2)' '
|
||||
|
||||
git status > output &&
|
||||
git status >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
|
||||
test_expect_success 'status -s (2)' '
|
||||
|
||||
git status -s >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
@@ -89,8 +107,8 @@ cat >expect <<EOF
|
||||
EOF
|
||||
test_expect_success 'status -uno' '
|
||||
mkdir dir3 &&
|
||||
: > dir3/untracked1 &&
|
||||
: > dir3/untracked2 &&
|
||||
: >dir3/untracked1 &&
|
||||
: >dir3/untracked2 &&
|
||||
git status -uno >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
@@ -101,6 +119,22 @@ test_expect_success 'status (status.showUntrackedFiles no)' '
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect << EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
EOF
|
||||
test_expect_success 'status -s -uno' '
|
||||
git config --unset status.showuntrackedfiles
|
||||
git status -s -uno >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
test_expect_success 'status -s (status.showUntrackedFiles no)' '
|
||||
git config status.showuntrackedfiles no
|
||||
git status -s >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
@@ -136,6 +170,29 @@ test_expect_success 'status (status.showUntrackedFiles normal)' '
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? dir3/
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
test_expect_success 'status -s -unormal' '
|
||||
git config --unset status.showuntrackedfiles
|
||||
git status -s -unormal >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
test_expect_success 'status -s (status.showUntrackedFiles normal)' '
|
||||
git config status.showuntrackedfiles normal
|
||||
git status -s >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
@@ -173,7 +230,30 @@ test_expect_success 'status (status.showUntrackedFiles all)' '
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat > expect << \EOF
|
||||
cat >expect <<EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
test_expect_success 'status -s -uall' '
|
||||
git config --unset status.showuntrackedfiles
|
||||
git status -s -uall >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
test_expect_success 'status -s (status.showUntrackedFiles all)' '
|
||||
git config status.showuntrackedfiles all
|
||||
git status -s >output &&
|
||||
rm -rf dir3 &&
|
||||
git config --unset status.showuntrackedfiles &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
@@ -199,12 +279,156 @@ EOF
|
||||
|
||||
test_expect_success 'status with relative paths' '
|
||||
|
||||
(cd dir1 && git status) > output &&
|
||||
(cd dir1 && git status) >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
cat > expect << \EOF
|
||||
cat >expect <<\EOF
|
||||
M modified
|
||||
A ../dir2/added
|
||||
?? untracked
|
||||
?? ../dir2/modified
|
||||
?? ../dir2/untracked
|
||||
?? ../expect
|
||||
?? ../output
|
||||
?? ../untracked
|
||||
EOF
|
||||
test_expect_success 'status -s with relative paths' '
|
||||
|
||||
(cd dir1 && git status -s) >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
|
||||
test_expect_success 'status --porcelain ignores relative paths setting' '
|
||||
|
||||
(cd dir1 && git status --porcelain) >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'setup unique colors' '
|
||||
|
||||
git config status.color.untracked blue
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
#
|
||||
# <GREEN>new file: dir2/added<RESET>
|
||||
#
|
||||
# Changed but not updated:
|
||||
# (use "git add <file>..." to update what will be committed)
|
||||
# (use "git checkout -- <file>..." to discard changes in working directory)
|
||||
#
|
||||
# <RED>modified: dir1/modified<RESET>
|
||||
#
|
||||
# Untracked files:
|
||||
# (use "git add <file>..." to include in what will be committed)
|
||||
#
|
||||
# <BLUE>dir1/untracked<RESET>
|
||||
# <BLUE>dir2/modified<RESET>
|
||||
# <BLUE>dir2/untracked<RESET>
|
||||
# <BLUE>expect<RESET>
|
||||
# <BLUE>output<RESET>
|
||||
# <BLUE>untracked<RESET>
|
||||
EOF
|
||||
|
||||
test_expect_success 'status with color.ui' '
|
||||
|
||||
git config color.ui always &&
|
||||
git status | test_decode_color >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'status with color.status' '
|
||||
|
||||
git config --unset color.ui &&
|
||||
git config color.status always &&
|
||||
git status | test_decode_color >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
<RED>M<RESET> dir1/modified
|
||||
<GREEN>A<RESET> dir2/added
|
||||
<BLUE>??<RESET> dir1/untracked
|
||||
<BLUE>??<RESET> dir2/modified
|
||||
<BLUE>??<RESET> dir2/untracked
|
||||
<BLUE>??<RESET> expect
|
||||
<BLUE>??<RESET> output
|
||||
<BLUE>??<RESET> untracked
|
||||
EOF
|
||||
|
||||
test_expect_success 'status -s with color.ui' '
|
||||
|
||||
git config --unset color.status &&
|
||||
git config color.ui always &&
|
||||
git status -s | test_decode_color >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'status -s with color.status' '
|
||||
|
||||
git config --unset color.ui &&
|
||||
git config color.status always &&
|
||||
git status -s | test_decode_color >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
|
||||
test_expect_success 'status --porcelain ignores color.ui' '
|
||||
|
||||
git config --unset color.status &&
|
||||
git config color.ui always &&
|
||||
git status --porcelain | test_decode_color >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'status --porcelain ignores color.status' '
|
||||
|
||||
git config --unset color.ui &&
|
||||
git config color.status always &&
|
||||
git status --porcelain | test_decode_color >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
# recover unconditionally from color tests
|
||||
git config --unset color.status
|
||||
git config --unset color.ui
|
||||
|
||||
cat >expect <<\EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
@@ -228,10 +452,29 @@ cat > expect << \EOF
|
||||
# untracked
|
||||
EOF
|
||||
|
||||
|
||||
test_expect_success 'status without relative paths' '
|
||||
|
||||
git config status.relativePaths false
|
||||
(cd dir1 && git status) > output &&
|
||||
(cd dir1 && git status) >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
|
||||
test_expect_success 'status -s without relative paths' '
|
||||
|
||||
(cd dir1 && git status -s) >output &&
|
||||
test_cmp expect output
|
||||
|
||||
'
|
||||
@@ -252,8 +495,8 @@ cat <<EOF >expect
|
||||
# output
|
||||
# untracked
|
||||
EOF
|
||||
test_expect_success 'status of partial commit excluding new file in index' '
|
||||
git status dir1/modified >output &&
|
||||
test_expect_success 'dry-run of partial commit excluding new file in index' '
|
||||
git commit --dry-run dir1/modified >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
@@ -302,6 +545,28 @@ test_expect_success 'status --untracked-files=all does not show submodule' '
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
A sm
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
test_expect_success 'status -s submodule summary is disabled by default' '
|
||||
git status -s >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
# we expect the same as the previous test
|
||||
test_expect_success 'status -s --untracked-files=all does not show submodule' '
|
||||
git status -s --untracked-files=all >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
head=$(cd sm && git rev-parse --short=7 --verify HEAD)
|
||||
|
||||
cat >expect <<EOF
|
||||
@@ -339,6 +604,21 @@ test_expect_success 'status submodule summary' '
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
M dir1/modified
|
||||
A dir2/added
|
||||
A sm
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
test_expect_success 'status -s submodule summary' '
|
||||
git status -s >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
# On branch master
|
||||
@@ -362,7 +642,23 @@ EOF
|
||||
test_expect_success 'status submodule summary (clean submodule)' '
|
||||
git commit -m "commit submodule" &&
|
||||
git config status.submodulesummary 10 &&
|
||||
test_must_fail git status >output &&
|
||||
test_must_fail git commit --dry-run >output &&
|
||||
test_cmp expect output &&
|
||||
git status >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
M dir1/modified
|
||||
?? dir1/untracked
|
||||
?? dir2/modified
|
||||
?? dir2/untracked
|
||||
?? expect
|
||||
?? output
|
||||
?? untracked
|
||||
EOF
|
||||
test_expect_success 'status -s submodule summary (clean submodule)' '
|
||||
git status -s >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
@@ -395,9 +691,9 @@ cat >expect <<EOF
|
||||
# output
|
||||
# untracked
|
||||
EOF
|
||||
test_expect_success 'status submodule summary (--amend)' '
|
||||
test_expect_success 'commit --dry-run submodule summary (--amend)' '
|
||||
git config status.submodulesummary 10 &&
|
||||
git status --amend >output &&
|
||||
git commit --dry-run --amend >output &&
|
||||
test_cmp expect output
|
||||
'
|
||||
|
||||
|
||||
@@ -49,4 +49,55 @@ test_expect_success 'merge c1 with c2, c3, c4, ... c29' '
|
||||
done
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
Trying simple merge with c2
|
||||
Trying simple merge with c3
|
||||
Trying simple merge with c4
|
||||
Merge made by octopus.
|
||||
c2.c | 1 +
|
||||
c3.c | 1 +
|
||||
c4.c | 1 +
|
||||
3 files changed, 3 insertions(+), 0 deletions(-)
|
||||
create mode 100644 c2.c
|
||||
create mode 100644 c3.c
|
||||
create mode 100644 c4.c
|
||||
EOF
|
||||
|
||||
test_expect_success 'merge output uses pretty names' '
|
||||
git reset --hard c1 &&
|
||||
git merge c2 c3 c4 >actual &&
|
||||
test_cmp actual expected
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
Already up-to-date with c4
|
||||
Trying simple merge with c5
|
||||
Merge made by octopus.
|
||||
c5.c | 1 +
|
||||
1 files changed, 1 insertions(+), 0 deletions(-)
|
||||
create mode 100644 c5.c
|
||||
EOF
|
||||
|
||||
test_expect_success 'merge up-to-date output uses pretty names' '
|
||||
git merge c4 c5 >actual &&
|
||||
test_cmp actual expected
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
Fast-forwarding to: c1
|
||||
Trying simple merge with c2
|
||||
Merge made by octopus.
|
||||
c1.c | 1 +
|
||||
c2.c | 1 +
|
||||
2 files changed, 2 insertions(+), 0 deletions(-)
|
||||
create mode 100644 c1.c
|
||||
create mode 100644 c2.c
|
||||
EOF
|
||||
|
||||
test_expect_success 'merge fast-forward output uses pretty names' '
|
||||
git reset --hard c0 &&
|
||||
git merge c1 c2 >actual &&
|
||||
test_cmp actual expected
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -105,6 +105,8 @@ do
|
||||
verbose=t; shift ;;
|
||||
-q|--q|--qu|--qui|--quie|--quiet)
|
||||
quiet=t; shift ;;
|
||||
--with-dashes)
|
||||
with_dashes=t; shift ;;
|
||||
--no-color)
|
||||
color=; shift ;;
|
||||
--no-python)
|
||||
@@ -211,6 +213,17 @@ test_set_editor () {
|
||||
export EDITOR
|
||||
}
|
||||
|
||||
test_decode_color () {
|
||||
sed -e 's/.\[1m/<WHITE>/g' \
|
||||
-e 's/.\[31m/<RED>/g' \
|
||||
-e 's/.\[32m/<GREEN>/g' \
|
||||
-e 's/.\[33m/<YELLOW>/g' \
|
||||
-e 's/.\[34m/<BLUE>/g' \
|
||||
-e 's/.\[35m/<MAGENTA>/g' \
|
||||
-e 's/.\[36m/<CYAN>/g' \
|
||||
-e 's/.\[m/<RESET>/g'
|
||||
}
|
||||
|
||||
test_tick () {
|
||||
if test -z "${test_tick+set}"
|
||||
then
|
||||
@@ -551,19 +564,8 @@ test_done () {
|
||||
# Test the binaries we have just built. The tests are kept in
|
||||
# t/ subdirectory and are run in 'trash directory' subdirectory.
|
||||
TEST_DIRECTORY=$(pwd)
|
||||
if test -z "$valgrind"
|
||||
if test -n "$valgrind"
|
||||
then
|
||||
if test -z "$GIT_TEST_INSTALLED"
|
||||
then
|
||||
PATH=$TEST_DIRECTORY/..:$PATH
|
||||
GIT_EXEC_PATH=$TEST_DIRECTORY/..
|
||||
else
|
||||
GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) ||
|
||||
error "Cannot run git from $GIT_TEST_INSTALLED."
|
||||
PATH=$GIT_TEST_INSTALLED:$TEST_DIRECTORY/..:$PATH
|
||||
GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
|
||||
fi
|
||||
else
|
||||
make_symlink () {
|
||||
test -h "$2" &&
|
||||
test "$1" = "$(readlink "$2")" || {
|
||||
@@ -625,6 +627,24 @@ else
|
||||
PATH=$GIT_VALGRIND/bin:$PATH
|
||||
GIT_EXEC_PATH=$GIT_VALGRIND/bin
|
||||
export GIT_VALGRIND
|
||||
elif test -n "$GIT_TEST_INSTALLED" ; then
|
||||
GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) ||
|
||||
error "Cannot run git from $GIT_TEST_INSTALLED."
|
||||
PATH=$GIT_TEST_INSTALLED:$TEST_DIRECTORY/..:$PATH
|
||||
GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
|
||||
else # normal case, use ../bin-wrappers only unless $with_dashes:
|
||||
git_bin_dir="$TEST_DIRECTORY/../bin-wrappers"
|
||||
if ! test -x "$git_bin_dir/git" ; then
|
||||
if test -z "$with_dashes" ; then
|
||||
say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
|
||||
fi
|
||||
with_dashes=t
|
||||
fi
|
||||
PATH="$git_bin_dir:$PATH"
|
||||
GIT_EXEC_PATH=$TEST_DIRECTORY/..
|
||||
if test -n "$with_dashes" ; then
|
||||
PATH="$TEST_DIRECTORY/..:$PATH"
|
||||
fi
|
||||
fi
|
||||
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
|
||||
unset GIT_CONFIG
|
||||
@@ -632,20 +652,29 @@ GIT_CONFIG_NOSYSTEM=1
|
||||
GIT_CONFIG_NOGLOBAL=1
|
||||
export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
|
||||
|
||||
. ../GIT-BUILD-OPTIONS
|
||||
|
||||
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
|
||||
export GITPERLLIB
|
||||
test -d ../templates/blt || {
|
||||
error "You haven't built things yet, have you?"
|
||||
}
|
||||
|
||||
if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON"
|
||||
then
|
||||
GITPYTHONLIB="$(pwd)/../git_remote_helpers/build/lib"
|
||||
export GITPYTHONLIB
|
||||
test -d ../git_remote_helpers/build || {
|
||||
error "You haven't built git_remote_helpers yet, have you?"
|
||||
}
|
||||
fi
|
||||
|
||||
if ! test -x ../test-chmtime; then
|
||||
echo >&2 'You need to build test-chmtime:'
|
||||
echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. ../GIT-BUILD-OPTIONS
|
||||
|
||||
# Test repository
|
||||
test="trash directory.$(basename "$0" .sh)"
|
||||
test -n "$root" && test="$root/$test"
|
||||
@@ -729,6 +758,7 @@ case $(uname -s) in
|
||||
esac
|
||||
|
||||
test -z "$NO_PERL" && test_set_prereq PERL
|
||||
test -z "$NO_PYTHON" && test_set_prereq PYTHON
|
||||
|
||||
# test whether the filesystem supports symbolic links
|
||||
ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user