Merge commit 'mingw/master' into devel

This commit is contained in:
Steffen Prohaska
2008-06-08 13:12:24 +02:00
278 changed files with 7808 additions and 2300 deletions

View File

@@ -89,6 +89,8 @@ For C programs:
of "else if" statements, it can make sense to add braces to
single line blocks.
- We try to avoid assignments inside if().
- Try to make your code understandable. You may put comments
in, but comments invariably tend to stale out when the code
they were describing changes. Often splitting a function

View File

@@ -3,7 +3,8 @@ MAN1_TXT= \
$(wildcard git-*.txt)) \
gitk.txt
MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt
MAN7_TXT=git.txt gitcli.txt
MAN7_TXT=git.txt gitcli.txt gittutorial.txt gittutorial-2.txt \
gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
@@ -11,16 +12,11 @@ MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
DOC_HTML=$(MAN_HTML)
ARTICLES = tutorial
ARTICLES += tutorial-2
ARTICLES += core-tutorial
ARTICLES += cvs-migration
ARTICLES += diffcore
ARTICLES = diffcore
ARTICLES += howto-index
ARTICLES += repository-layout
ARTICLES += everyday
ARTICLES += git-tools
ARTICLES += glossary
# with their own formatting rules.
SP_ARTICLES = howto/revert-branch-rebase howto/using-merge-subtree user-manual
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))

View File

@@ -0,0 +1,27 @@
GIT v1.5.5.2 Release Notes
==========================
Fixes since v1.5.5.1
--------------------
* "git repack -n" was mistakenly made no-op earlier.
* "git imap-send" wanted to always have imap.host even when use of
imap.tunnel made it unnecessary.
* reflog syntax that uses time e.g. "HEAD@{10 seconds ago}:path" did not
stop parsing at the closing "}".
* "git rev-parse --symbolic-full-name ^master^2" printed solitary "^",
but it should print nothing.
* "git commit" did not detect when it failed to write tree objects.
* "git fetch" sometimes transferred too many objects unnecessarily.
* a path specification "a/b" in .gitattributes file should not match
"sub/a/b".
* various gitweb fixes.
Also comes with various documentation updates.

View File

@@ -0,0 +1,12 @@
GIT v1.5.5.3 Release Notes
==========================
Fixes since v1.5.5.2
--------------------
* "git send-email --compose" did not notice that non-ascii contents
needed some MIME magic.
* "git fast-export" did not export octopus merges correctly.
Also comes with various documentation updates.

View File

@@ -6,16 +6,30 @@ Updates since v1.5.5
(subsystems)
* Comes with updated gitk and git-gui.
(portability)
* git will build on AIX better than before now.
* core.ignorecase configuration variable can be used to work better on
filesystems that are not case sensitive.
* "git init" now autodetects the case sensitivity of the filesystem and
sets core.ignorecase accordingly.
(performance)
* "git clone" was rewritten in C. This will hopefully help cloning a
repository with insane number of refs.
* "git rebase --onto $there $from $branch" used to switch to the tip of
$branch only to immediately reset back to $from, smudging work tree
files unnecessarily. This has been optimized.
* Object creation codepath in "git-svn" has been optimized by enhancing
plumbing commands git-cat-file and git-hash-object.
(usability, bells and whistles)
* "git add -p" (and the "patch" subcommand of "git add -i") can choose to
@@ -23,20 +37,57 @@ Updates since v1.5.5
* "git bisect help" gives longer and more helpful usage information.
* "git bisect" does not use a special branch "bisect" anymore; instead, it
does its work on a detached HEAD.
* "git branch" (and "git checkout -b") can be told to set up
branch.<name>.rebase automatically, so that later you can say "git pull"
and magically cause "git pull --rebase" to happen.
* "git branch --merged" and "git branch --no-merged" can be used to list
branches that have already been merged (or not yet merged) to the
current branch.
* "git cherry-pick" and "git revert" can add a sign-off.
* "git commit" mentions the author identity when you are committing
somebody else's changes.
* "git diff/log --dirstat" output is consistent between binary and textual
changes.
* "git filter-branch" rewrites signed tags by demoting them to annotated.
* "git format-patch --no-binary" can produce a patch that lack binary
changes (i.e. cannot be used to propagate the whole changes) meant only
for reviewing.
* "git init --bare" is a synonym for "git --bare init" now.
* "git gc --auto" honors a new pre-aut-gc hook to temporarily disable it.
* "git log --pretty=tformat:<custom format>" gives a LF after each entry,
instead of giving a LF between each pair of entries which is how
"git log --pretty=format:<custom format>" works.
* "git log" and friends learned the "--graph" option to show the ancestry
graph at the left margin of the output.
* "git log" and friends can be told to use date format that is different
from the default via 'log.date' configuration variable.
* "git send-email" now can send out messages outside a git repository.
* "git send-email --compose" was made aware of rfc2047 quoting.
* "git status" can optionally include output from "git submodule
summary".
* "git svn" learned --add-author-from option to propagate the authorship
by munging the commit log message.
* new object creation and looking up in "git svn" has been optimized.
* "gitweb" can read from a system-wide configuration file.
(internal)
@@ -54,6 +105,6 @@ this release, unless otherwise noted.
--
exec >/var/tmp/1
O=v1.5.5-56-g5f0734f
O=v1.5.6-rc1
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint

View File

@@ -205,10 +205,13 @@ Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
handling).
core.ignoreStat::
The working copy files are assumed to stay unchanged until you
mark them otherwise manually - Git will not detect the file changes
by lstat() calls. This is useful on systems where those are very
slow, such as Microsoft Windows. See linkgit:git-update-index[1].
If true, commands which modify both the working tree and the index
will mark the updated paths with the "assume unchanged" bit in the
index. These marked files are then assumed to stay unchanged in the
working copy, until you mark them otherwise manually - Git will not
detect the file changes by lstat() calls. This is useful on systems
where those are very slow, such as Microsoft Windows.
See linkgit:git-update-index[1].
False by default.
core.preferSymlinkRefs::
@@ -523,8 +526,10 @@ color.status.<slot>::
one of `header` (the header text of the status message),
`added` or `updated` (files which are added but not committed),
`changed` (files which are changed but not added in the index),
or `untracked` (files which are not tracked by git). The values of
these variables may be specified as in color.branch.<slot>.
`untracked` (files which are not tracked by git), or
`nobranch` (the color the 'no branch' warning is shown in, defaulting
to red). The values of these variables may be specified as in
color.branch.<slot>.
commit.template::
Specify a file to use as the template for new commit messages.
@@ -660,11 +665,24 @@ gitcvs.logfile::
Path to a log file where the CVS server interface well... logs
various stuff. See linkgit:git-cvsserver[1].
gitcvs.usecrlfattr
If true, the server will look up the `crlf` attribute for
files to determine the '-k' modes to use. If `crlf` is set,
the '-k' mode will be left blank, so cvs clients will
treat it as text. If `crlf` is explicitly unset, the file
will be set with '-kb' mode, which supresses any newline munging
the client might otherwise do. If `crlf` is not specified,
then 'gitcvs.allbinary' is used. See linkgit:gitattribute[5].
gitcvs.allbinary::
If true, all files are sent to the client in mode '-kb'. This
causes the client to treat all files as binary files which suppresses
any newline munging it otherwise might do. A work-around for the
fact that there is no way yet to set single files to mode '-kb'.
This is used if 'gitcvs.usecrlfattr' does not resolve
the correct '-kb' mode to use. If true, all
unresolved files are sent to the client in
mode '-kb'. This causes the client to treat them
as binary files, which suppresses any newline munging it
otherwise might do. Alternatively, if it is set to "guess",
then the contents of the file are examined to decide if
it is binary, similar to 'core.autocrlf'.
gitcvs.dbname::
Database used by git-cvsserver to cache revision information
@@ -695,8 +713,9 @@ gitcvs.dbTableNamePrefix::
linkgit:git-cvsserver[1] for details). Any non-alphabetic
characters will be replaced with underscores.
All gitcvs variables except for 'gitcvs.allbinary' can also be
specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'
All gitcvs variables except for 'gitcvs.usecrlfattr' and
'gitcvs.allbinary' can also be specified as
'gitcvs.<access_method>.<varname>' (where 'access_method'
is one of "ext" and "pserver") to make them apply only for the given
access method.
@@ -815,6 +834,12 @@ instaweb.port::
The port number to bind the gitweb httpd to. See
linkgit:git-instaweb[1].
log.date::
Set default date-time mode for the log command. Setting log.date
value is similar to using git log's --date option. The value is one of
following alternatives: {relative,local,default,iso,rfc,short}.
See linkgit:git-log[1].
log.showroot::
If true, the initial commit will be shown as a big creation event.
This is equivalent to a diff against an empty tree.

View File

@@ -228,6 +228,9 @@ endif::git-format-patch[]
--no-ext-diff::
Disallow external diff drivers.
--ignore-submodules::
Ignore changes to submodules in the diff generation.
--src-prefix=<prefix>::
Show the given source prefix instead of "a/".

View File

@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [-u] [--refresh]
[--] <filepattern>...
[--ignore-errors] [--] <filepattern>...
DESCRIPTION
-----------
@@ -83,6 +83,11 @@ OPTIONS
Don't add the file(s), but only refresh their stat()
information in the index.
\--ignore-errors::
If some files could not be added because of errors indexing
them, do not abort the operation, but continue adding the
others. The command shall still exit with non-zero status.
\--::
This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken
@@ -241,7 +246,7 @@ characters that need C-quoting. `core.quotepath` configuration can be
used to work this limitation around to some degree, but backslash,
double-quote and control characters will still have problems.
See Also
SEE ALSO
--------
linkgit:git-status[1]
linkgit:git-rm[1]

View File

@@ -9,7 +9,7 @@ git-bundle - Move objects and refs by archive
SYNOPSIS
--------
[verse]
'git-bundle' create <file> [git-rev-list args]
'git-bundle' create <file> <git-rev-list args>
'git-bundle' verify <file>
'git-bundle' list-heads <file> [refname...]
'git-bundle' unbundle <file> [refname...]

View File

@@ -9,12 +9,16 @@ git-cat-file - Provide content or type/size information for repository objects
SYNOPSIS
--------
'git-cat-file' [-t | -s | -e | -p | <type>] <object>
'git-cat-file' [--batch | --batch-check] < <list-of-objects>
DESCRIPTION
-----------
Provides content or type of objects in the repository. The type
is required unless '-t' or '-p' is used to find the object type,
or '-s' is used to find the object size.
In the first form, provides content or type of objects in the repository. The
type is required unless '-t' or '-p' is used to find the object type, or '-s'
is used to find the object size.
In the second form, a list of object (separated by LFs) is provided on stdin,
and the SHA1, type, and size of each object is printed on stdout.
OPTIONS
-------
@@ -46,6 +50,14 @@ OPTIONS
or to ask for a "blob" with <object> being a tag object that
points at it.
--batch::
Print the SHA1, type, size, and contents of each object provided on
stdin. May not be combined with any other options or arguments.
--batch-check::
Print the SHA1, type, and size of each object provided on stdin. May not be
combined with any other options or arguments.
OUTPUT
------
If '-t' is specified, one of the <type>.
@@ -56,9 +68,30 @@ If '-e' is specified, no output.
If '-p' is specified, the contents of <object> are pretty-printed.
Otherwise the raw (though uncompressed) contents of the <object> will
be returned.
If <type> is specified, the raw (though uncompressed) contents of the <object>
will be returned.
If '--batch' is specified, output of the following form is printed for each
object specified on stdin:
------------
<sha1> SP <type> SP <size> LF
<contents> LF
------------
If '--batch-check' is specified, output of the following form is printed for
each object specified fon stdin:
------------
<sha1> SP <type> SP <size> LF
------------
For both '--batch' and '--batch-check', output of the following form is printed
for each object specified on stdin that does not exist in the repository:
------------
<object> SP missing LF
------------
Author
------

View File

@@ -13,6 +13,8 @@ DESCRIPTION
-----------
The changeset (or "diff") of each commit between the fork-point and <head>
is compared against each commit between the fork-point and <upstream>.
The commits are compared with their 'patch id', obtained from linkgit:git-patch-id[1]
program.
Every commit that doesn't exist in the <upstream> branch
has its id (sha1) reported, prefixed by a symbol. The ones that have
@@ -56,6 +58,10 @@ OPTIONS
<limit>::
Do not report commits up to (and including) limit.
SEE ALSO
--------
linkgit:git-patch-id[1]
Author
------
Written by Junio C Hamano <junkio@cox.net>

View File

@@ -88,7 +88,7 @@ Discussion
include::i18n.txt[]
See Also
SEE ALSO
--------
linkgit:git-write-tree[1]

View File

@@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
SYNOPSIS
--------
'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-W] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
DESCRIPTION
@@ -65,11 +65,22 @@ OPTIONS
-w::
Specify the location of the CVS checkout to use for the export. This
option does not require GIT_DIR to be set before execution if the
current directory is within a git repository.
current directory is within a git repository. The default is the
value of 'cvsexportcommit.cvsdir'.
-W::
Tell cvsexportcommit that the current working directory is not only
a Git checkout, but also the CVS checkout. Therefore, Git will
reset the working directory to the parent commit before proceeding.
-v::
Verbose.
CONFIGURATION
-------------
cvsexportcommit.cvsdir::
The default location of the CVS checkout to use for the export.
EXAMPLES
--------

View File

@@ -301,11 +301,33 @@ checkout, diff, status, update, log, add, remove, commit.
Legacy monitoring operations are not supported (edit, watch and related).
Exports and tagging (tags and branches) are not supported at this stage.
The server should set the '-k' mode to binary when relevant, however,
this is not really implemented yet. For now, you can force the server
to set '-kb' for all files by setting the `gitcvs.allbinary` config
variable. In proper GIT tradition, the contents of the files are
always respected. No keyword expansion or newline munging is supported.
CRLF Line Ending Conversions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default the server leaves the '-k' mode blank for all files,
which causes the cvs client to treat them as a text files, subject
to crlf conversion on some platforms.
You can make the server use `crlf` attributes to set the '-k' modes
for files by setting the `gitcvs.usecrlfattr` config variable.
In this case, if `crlf` is explicitly unset ('-crlf'), then the
server will set '-kb' mode for binary files. If `crlf` is set,
then the '-k' mode will explicitly be left blank. See
also linkgit:gitattributes[5] for more information about the `crlf`
attribute.
Alternatively, if `gitcvs.usecrlfattr` config is not enabled
or if the `crlf` attribute is unspecified for a filename, then
the server uses the `gitcvs.allbinary` config for the default setting.
If `gitcvs.allbinary` is set, then file not otherwise
specified will default to '-kb' mode. Otherwise the '-k' mode
is left blank. But if `gitcvs.allbinary` is set to "guess", then
the correct '-k' mode will be guessed based on the contents of
the file.
For best consistency with cvs, it is probably best to override the
defaults by setting `gitcvs.usecrlfattr` to true,
and `gitcvs.allbinary` to "guess".
Dependencies
------------

View File

@@ -174,7 +174,7 @@ upload-pack::
upload-archive::
This serves `git-archive --remote`. It is disabled by
default, but a repository can enable it by setting
`daemon.uploadarchive` configuration item to `true`.
`daemon.uploadarch` configuration item to `true`.
receive-pack::
This serves `git-send-pack` clients, allowing anonymous
@@ -257,7 +257,7 @@ selectively enable/disable services per repository::
----------------------------------------------------------------
[daemon]
uploadpack = false
uploadarchive = true
uploadarch = true
----------------------------------------------------------------

View File

@@ -8,7 +8,7 @@ git-diff-files - Compares files in the working tree and the index
SYNOPSIS
--------
'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|--no-index] [<common diff options>] [<path>...]
'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc] [<common diff options>] [<path>...]
DESCRIPTION
-----------
@@ -36,9 +36,6 @@ omit diff output for unmerged entries and just show "Unmerged".
diff, similar to the way 'diff-tree' shows a merge
commit with these flags.
--no-index::
Compare the two given files / directories.
-q::
Remain silent even on nonexistent files

View File

@@ -113,7 +113,7 @@ OPTIONS
stdin. The commit id is expected on stdout.
+
As a special extension, the commit filter may emit multiple
commit ids; in that case, ancestors of the original commit will
commit ids; in that case, the rewritten children of the original commit will
have all of them as parents.
+
You can use the 'map' convenience function in this filter, and other

View File

@@ -223,7 +223,7 @@ as e-mailable patches:
$ git format-patch -3
------------
See Also
SEE ALSO
--------
linkgit:git-am[1], linkgit:git-send-email[1]

View File

@@ -119,7 +119,7 @@ If you are expecting some objects to be collected and they aren't, check
all of those locations and decide whether it makes sense in your case to
remove those references.
See Also
SEE ALSO
--------
linkgit:git-prune[1]
linkgit:git-reflog[1]

View File

@@ -79,9 +79,9 @@ git gui browser maint::
selected in the browser can be viewed with the internal
blame viewer.
See Also
SEE ALSO
--------
'gitk(1)'::
linkgit:gitk[1]::
The git repository browser. Shows branches, commit history
and file differences. gitk is the utility started by
git-gui's Repository Visualize actions.

View File

@@ -8,7 +8,7 @@ git-hash-object - Compute object ID and optionally creates a blob from a file
SYNOPSIS
--------
'git-hash-object' [-t <type>] [-w] [--stdin] [--] <file>...
'git-hash-object' [-t <type>] [-w] [--stdin | --stdin-paths] [--] <file>...
DESCRIPTION
-----------
@@ -32,6 +32,9 @@ OPTIONS
--stdin::
Read the object from standard input instead of from a file.
--stdin-paths::
Read file names from stdin instead of from the command-line.
Author
------
Written by Junio C Hamano <junkio@cox.net>

View File

@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
SYNOPSIS
--------
'git-init' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
'git-init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
OPTIONS
@@ -20,6 +20,11 @@ OPTIONS
Only print error and warning messages, all other output will be suppressed.
--bare::
Create a bare repository. If GIT_DIR environment is not set, it is set to the
current working directory.
--template=<template_directory>::
Provide the directory from which templates will be used. The default template

View File

@@ -177,7 +177,7 @@ top of the directory tree. A pattern read from a file specified
by --exclude-per-directory is relative to the directory that the
pattern file appears in.
See Also
SEE ALSO
--------
linkgit:git-read-tree[1], linkgit:gitignore[5]

View File

@@ -200,7 +200,7 @@ Documentation
-------------
Documentation by Junio C Hamano
See Also
SEE ALSO
--------
linkgit:git-rev-list[1]
linkgit:git-repack[1]

View File

@@ -46,7 +46,7 @@ Documentation
--------------
Documentation by Lukas Sandström <lukass@etek.chalmers.se>
See Also
SEE ALSO
--------
linkgit:git-pack-objects[1]
linkgit:git-repack[1]

View File

@@ -42,7 +42,7 @@ Documentation
--------------
Documentation by Ryan Anderson <ryan@michonline.com>
See Also
SEE ALSO
--------
linkgit:git-pack-objects[1]
linkgit:git-repack[1]

View File

@@ -66,7 +66,7 @@ many other housekeeping tasks.
For a description of which objects are considered for pruning, see
git-fsck's --unreachable option.
See Also
SEE ALSO
--------
linkgit:git-fsck[1],

View File

@@ -46,12 +46,6 @@ specified, the same ref that <src> referred to locally). If
the optional leading plus `+` is used, the remote ref is updated
even if it does not result in a fast forward update.
+
Note: If no explicit refspec is found, (that is neither
on the command line nor in any Push line of the
corresponding remotes file---see below), then "matching" heads are
pushed: for every head that exists on the local side, the remote side is
updated if a head of the same name already exists on the remote side.
+
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
+
A parameter <ref> without a colon pushes the <ref> from the source
@@ -59,6 +53,13 @@ repository to the destination repository under the same name.
+
Pushing an empty <src> allows you to delete the <dst> ref from
the remote repository.
+
The special refspec `:` (or `+:` to allow non-fast forward updates)
directs git to push "matching" heads: for every head that exists on
the local side, the remote side is updated if a head of the same name
already exists on the remote side. This is the default operation mode
if no explicit refspec is found (that is neither on the command line
nor in any Push line of the corresponding remotes file---see below).
\--all::
Instead of naming each ref to push, specifies that all

View File

@@ -345,7 +345,7 @@ middle of doing, and when your working tree is ready (i.e. you
have finished your work-in-progress), attempt the merge again.
See Also
SEE ALSO
--------
linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
linkgit:gitignore[5]

View File

@@ -128,7 +128,7 @@ $ git merge origin
------------
See Also
SEE ALSO
--------
linkgit:git-fetch[1]
linkgit:git-branch[1]

View File

@@ -8,7 +8,7 @@ git-repack - Pack unpacked objects in a repository
SYNOPSIS
--------
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
'git-repack' [-a] [-A] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
DESCRIPTION
-----------
@@ -37,6 +37,18 @@ OPTIONS
leaves behind, but `git fsck --full` shows as
dangling.
-A::
Same as `-a`, but any unreachable objects in a previous
pack become loose, unpacked objects, instead of being
left in the old pack. Unreachable objects are never
intentionally added to a pack, even when repacking.
When used with '-d', this option
prevents unreachable objects from being immediately
deleted by way of being left in the old pack and then
removed. Instead, the loose unreachable objects
will be pruned according to normal expiry rules
with the next linkgit:git-gc[1].
-d::
After packing, if the newly created packs make some
existing packs redundant, remove the redundant packs.
@@ -55,8 +67,11 @@ OPTIONS
linkgit:git-pack-objects[1].
-n::
Do not update the server information with
`git update-server-info`.
Do not update the server information with
`git update-server-info`. This option skips
updating local catalog files needed to publish
this repository (or a direct copy of it)
over HTTP or FTP. See gitlink:git-update-server-info[1].
--window=[N], --depth=[N]::
These two options affect how the objects contained in the pack are
@@ -107,7 +122,7 @@ Documentation
--------------
Documentation by Ryan Anderson <ryan@michonline.com>
See Also
SEE ALSO
--------
linkgit:git-pack-objects[1]
linkgit:git-prune-packed[1]

View File

@@ -243,16 +243,18 @@ Here is an illustration, by Jon Loeliger. Both commit nodes B
and C are parents of commit node A. Parent commits are ordered
left-to-right.
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
........................................
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
........................................
A = = A^0
B = A^ = A^1 = A~1
@@ -378,6 +380,31 @@ C? option C with an optional argument"
eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
------------
EXAMPLES
--------
* Print the object name of the current commit:
+
------------
$ git rev-parse --verify HEAD
------------
* Print the commit object name from the revision in the $REV shell variable:
+
------------
$ git rev-parse --verify $REV
------------
+
This will error out if $REV is empty or not a valid revision.
* Same as above:
+
------------
$ git rev-parse --default master --verify $REV
------------
+
but if $REV is empty, the commit object name from master will be printed.
Author
------

View File

@@ -93,7 +93,7 @@ git-rm -f git-*.sh::
(i.e. you are listing the files explicitly), it
does not remove `subdir/git-foo.sh`.
See Also
SEE ALSO
--------
linkgit:git-add[1]

View File

@@ -79,8 +79,6 @@ Documentation
-------------
Documentation by David Greaves, Petr Baudis and the git-list <git@vger.kernel.org>.
This manual page is a stub. You can help the git documentation by expanding it.
GIT
---
Part of the linkgit:git[7] suite

View File

@@ -57,7 +57,7 @@ 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]).
See Also
SEE ALSO
--------
linkgit:gitignore[5]

View File

@@ -61,6 +61,16 @@ COMMANDS
Set the 'useSvnsyncProps' option in the [svn-remote] config.
--rewrite-root=<URL>;;
Set the 'rewriteRoot' option in the [svn-remote] config.
--use-log-author;;
When retrieving svn commits into git (as part of fetch, rebase, or
dcommit operations), look for the first From: or Signed-off-by: line
in the log message and use that as the author string.
--add-author-from;;
When committing to svn from git (as part of commit or dcommit
operations), if the existing log message doesn't already have a
From: or Signed-off-by: line, append a From: line based on the
git commit's author string. If you use this, then --use-log-author
will retrieve a valid author string for all commits.
--username=<USER>;;
For transports that SVN handles authentication for (http,
https, and plain svn), specify the username. For other
@@ -196,10 +206,10 @@ Any other arguments are passed directly to `git log'
independently of git-svn functions.
'create-ignore'::
Recursively finds the svn:ignore property on directories and
creates matching .gitignore files. The resulting files are staged to
be committed, but are not committed.
be committed, but are not committed. Use -r/--revision to refer to a
specfic revision.
'show-ignore'::
Recursively finds and lists the svn:ignore property on
@@ -223,6 +233,19 @@ Any other arguments are passed directly to `git log'
argument. Use the --url option to output only the value of the
'URL:' field.
'proplist'::
Lists the properties stored in the Subversion repository about a
given file or directory. Use -r/--revision to refer to a specific
Subversion revision.
'propget'::
Gets the Subversion property given as the first argument, for a
file. A specific revision can be specified with -r/--revision.
'show-externals'::
Shows the Subversion externals. Use -r/--revision to specify a
specific revision.
--
OPTIONS
@@ -342,11 +365,15 @@ Passed directly to git-rebase when using 'dcommit' if a
-n::
--dry-run::
This is only used with the 'dcommit' command.
This can be used with the 'dcommit' and 'rebase' commands.
Print out the series of git arguments that would show
For 'dcommit', print out the series of git arguments that would show
which diffs would be committed to SVN.
For 'rebase', display the local branch associated with the upstream svn
repository associated with the current branch and the URL of svn
repository that will be fetched from.
--
ADVANCED OPTIONS

View File

@@ -15,6 +15,7 @@ SYNOPSIS
[--cacheinfo <mode> <object> <file>]\*
[--chmod=(+|-)x]
[--assume-unchanged | --no-assume-unchanged]
[--ignore-submodules]
[--really-refresh] [--unresolve] [--again | -g]
[--info-only] [--index-info]
[-z] [--stdin]
@@ -54,6 +55,10 @@ OPTIONS
default behavior is to error out. This option makes
git-update-index continue anyway.
--ignore-submodules:
Do not try to update submodules. This option is only respected
when passed before --refresh.
--unmerged::
If --refresh finds unmerged changes in the index, the default
behavior is to error out. This option makes git-update-index
@@ -307,7 +312,7 @@ The command looks at `core.ignorestat` configuration variable. See
'Using "assume unchanged" bit' section above.
See Also
SEE ALSO
--------
linkgit:git-config[1],
linkgit:git-add[1]

View File

@@ -45,7 +45,7 @@ Your parents must have hated you!::
Your sysadmin must hate you!::
The password(5) name field is longer than a giant static buffer.
See Also
SEE ALSO
--------
linkgit:git-commit-tree[1]
linkgit:git-tag[1]

View File

@@ -20,10 +20,10 @@ Git is a fast, scalable, distributed revision control system with an
unusually rich command set that provides both high-level operations
and full access to internals.
See this link:tutorial.html[tutorial] to get started, then see
See this linkgit:gittutorial[7][tutorial] to get started, then see
link:everyday.html[Everyday Git] for a useful minimum set of commands, and
"man git-commandname" for documentation of each command. CVS users may
also want to read link:cvs-migration.html[CVS migration]. See
also want to read linkgit:gitcvs-migration[7][CVS migration]. See
link:user-manual.html[Git User's Manual] for a more in-depth
introduction.
@@ -46,10 +46,12 @@ Documentation for older releases are available here:
* link:v1.5.5/git.html[documentation for release 1.5.5]
* release notes for
link:RelNotes-1.5.5.3.txt[1.5.5.3],
link:RelNotes-1.5.5.2.txt[1.5.5.2],
link:RelNotes-1.5.5.1.txt[1.5.5.1],
link:RelNotes-1.5.5.txt[1.5.5].
* link:v1.5.5.1/git.html[documentation for release 1.5.5.1]
* link:v1.5.5.3/git.html[documentation for release 1.5.5.3]
* link:v1.5.4.5/git.html[documentation for release 1.5.4.5]
@@ -172,7 +174,7 @@ See the references above to get started using git. The following is
probably more detail than necessary for a first-time user.
The link:user-manual.html#git-concepts[git concepts chapter of the
user-manual] and the link:core-tutorial.html[Core tutorial] both provide
user-manual] and the linkgit:gitcore-tutorial[7][Core tutorial] both provide
introductions to the underlying git architecture.
See also the link:howto-index.html[howto] documents for some useful
@@ -372,7 +374,7 @@ Higher level SCMs may provide and manage additional information in the
Terminology
-----------
Please see the link:glossary.html[glossary] document.
Please see the linkgit:gitglossary[7][glossary] document.
Environment Variables
@@ -516,7 +518,7 @@ Discussion[[Discussion]]
More detail on the following is available from the
link:user-manual.html#git-concepts[git concepts chapter of the
user-manual] and the link:core-tutorial.html[Core tutorial].
user-manual] and the linkgit:gitcore-tutorial[7][Core tutorial].
A git project normally consists of a working directory with a ".git"
subdirectory at the top level. The .git directory contains, among other
@@ -577,6 +579,13 @@ The documentation for git suite was started by David Greaves
<david@dgreaves.com>, and later enhanced greatly by the
contributors on the git-list <git@vger.kernel.org>.
SEE ALSO
--------
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite

View File

@@ -1,14 +1,22 @@
A git core tutorial for developers
==================================
gitcore-tutorial(7)
===================
Introduction
------------
NAME
----
gitcore-tutorial - A git core tutorial for developers
SYNOPSIS
--------
git *
DESCRIPTION
-----------
This tutorial explains how to use the "core" git programs to set up and
work with a git repository.
If you just need to use git as a revision control system you may prefer
to start with link:tutorial.html[a tutorial introduction to git] or
to start with linkgit:gittutorial[7][a tutorial introduction to git] or
link:user-manual.html[the git user manual].
However, an understanding of these low-level tools can be helpful if
@@ -1581,7 +1589,7 @@ suggested in the previous section may be new to you. You do not
have to worry. git supports "shared public repository" style of
cooperation you are probably more familiar with as well.
See link:cvs-migration.html[git for CVS users] for the details.
See linkgit:gitcvs-migration[7][git for CVS users] for the details.
Bundling your work together
---------------------------
@@ -1679,3 +1687,13 @@ merge two at a time, documenting how you resolved the conflicts,
and the reason why you preferred changes made in one side over
the other. Otherwise it would make the project history harder
to follow, not easier.
SEE ALSO
--------
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite.

View File

@@ -1,5 +1,16 @@
git for CVS users
=================
gitcvs-migration(7)
===================
NAME
----
gitcvs-migration - git for CVS users
SYNOPSIS
--------
git cvsimport *
DESCRIPTION
-----------
Git differs from CVS in that every working tree contains a repository with
a full copy of the project history, and no repository is inherently more
@@ -8,8 +19,8 @@ designating a single shared repository which people can synchronize with;
this document explains how to do that.
Some basic familiarity with git is required. This
link:tutorial.html[tutorial introduction to git] and the
link:glossary.html[git glossary] should be sufficient.
linkgit:gittutorial[7][tutorial introduction to git] and the
linkgit:gitglossary[7][git glossary] should be sufficient.
Developing against a shared repository
--------------------------------------
@@ -71,7 +82,7 @@ Setting Up a Shared Repository
We assume you have already created a git repository for your project,
possibly created from scratch or from a tarball (see the
link:tutorial.html[tutorial]), or imported from an already existing CVS
linkgit:gittutorial[7][tutorial]), or imported from an already existing CVS
repository (see the next section).
Assume your existing repo is at /home/alice/myproject. Create a new "bare"
@@ -170,3 +181,16 @@ variants of this model.
With a small group, developers may just pull changes from each other's
repositories without the need for a central maintainer.
SEE ALSO
--------
linkgit:gittutorial[7],
linkgit:gittutorial-2[7],
linkgit:gitcore-tutorial[7],
linkgit:gitglossary[7],
link:everyday.html[Everyday Git],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite.

View File

@@ -0,0 +1,25 @@
gitglossary(7)
==============
NAME
----
gitglossary - A GIT Glossary
SYNOPSIS
--------
*
DESCRIPTION
-----------
include::glossary-content.txt[]
SEE ALSO
--------
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite.

View File

@@ -85,7 +85,7 @@ Files
Gitk creates the .gitk file in your $HOME directory to store preferences
such as display options, font, and colors.
See Also
SEE ALSO
--------
'qgit(1)'::
A repository browser written in C++ using Qt.

View File

@@ -1,7 +1,18 @@
A tutorial introduction to git: part two
========================================
gittutorial-2(7)
================
You should work through link:tutorial.html[A tutorial introduction to
NAME
----
gittutorial-2 - A tutorial introduction to git: part two
SYNOPSIS
--------
git *
DESCRIPTION
-----------
You should work through linkgit:gittutorial[7][A tutorial introduction to
git] before reading this tutorial.
The goal of this tutorial is to introduce two fundamental pieces of
@@ -379,7 +390,7 @@ in the index file is identical to the one in the working directory.
In addition to being the staging area for new commits, the index file
is also populated from the object database when checking out a
branch, and is used to hold the trees involved in a merge operation.
See the link:core-tutorial.html[core tutorial] and the relevant man
See the linkgit:gitcore-tutorial[7][core tutorial] and the relevant man
pages for details.
What next?
@@ -389,18 +400,31 @@ At this point you should know everything necessary to read the man
pages for any of the git commands; one good place to start would be
with the commands mentioned in link:everyday.html[Everyday git]. You
should be able to find any unknown jargon in the
link:glossary.html[Glossary].
linkgit:gitglossary[7][Glossary].
The link:user-manual.html[Git User's Manual] provides a more
comprehensive introduction to git.
The link:cvs-migration.html[CVS migration] document explains how to
The linkgit:gitcvs-migration[7][CVS migration] document explains how to
import a CVS repository into git, and shows how to use git in a
CVS-like way.
For some interesting examples of git use, see the
link:howto-index.html[howtos].
For git developers, the link:core-tutorial.html[Core tutorial] goes
For git developers, the linkgit:gitcore-tutorial[7][Core tutorial] goes
into detail on the lower-level git mechanisms involved in, for
example, creating a new commit.
SEE ALSO
--------
linkgit:gittutorial[7],
linkgit:gitcvs-migration[7],
linkgit:gitcore-tutorial[7],
linkgit:gitglossary[7],
link:everyday.html[Everyday git],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite.

View File

@@ -1,5 +1,16 @@
A tutorial introduction to git (for version 1.5.1 or newer)
===========================================================
gittutorial(7)
==============
NAME
----
gittutorial - A tutorial introduction to git (for version 1.5.1 or newer)
SYNOPSIS
--------
git *
DESCRIPTION
-----------
This tutorial explains how to import a new project into git, make
changes to it, and share changes with other developers.
@@ -381,7 +392,7 @@ see linkgit:git-pull[1] for details.
Git can also be used in a CVS-like mode, with a central repository
that various users push changes to; see linkgit:git-push[1] and
link:cvs-migration.html[git for CVS users].
linkgit:gitcvs-migration[7][git for CVS users].
Exploring history
-----------------
@@ -560,7 +571,7 @@ is based:
used to create commits, check out working directories, and
hold the various trees involved in a merge.
link:tutorial-2.html[Part two of this tutorial] explains the object
linkgit:gittutorial-2[7][Part two of this tutorial] explains the object
database, the index file, and a few other odds and ends that you'll
need to make the most of git.
@@ -581,4 +592,17 @@ digressions that may be interesting at this point are:
* link:everyday.html[Everyday GIT with 20 Commands Or So]
* link:cvs-migration.html[git for CVS users].
* linkgit:gitcvs-migration[7][git for CVS users].
SEE ALSO
--------
linkgit:gittutorial-2[7],
linkgit:gitcvs-migration[7],
linkgit:gitcore-tutorial[7],
linkgit:gitglossary[7],
link:everyday.html[Everyday git],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite.

View File

@@ -1,6 +1,3 @@
GIT Glossary
============
[[def_alternate_object_database]]alternate object database::
Via the alternates mechanism, a <<def_repository,repository>>
can inherit part of its <<def_object_database,object database>>
@@ -90,11 +87,10 @@ to point at the new commit.
source code management tools.
[[def_DAG]]DAG::
Directed acyclic graph. The <<def_commit,commit>> objects form a
Directed acyclic graph. The <<def_commit_object,commit objects>> form a
directed acyclic graph, because they have parents (directed), and the
graph of commit objects is acyclic (there is no
<<def_chain,chain>> which begins and ends with the same
<<def_object,object>>).
graph of commit objects is acyclic (there is no <<def_chain,chain>>
which begins and ends with the same <<def_object,object>>).
[[def_dangling_object]]dangling object::
An <<def_unreachable_object,unreachable object>> which is not
@@ -250,9 +246,10 @@ This commit is referred to as a "merge commit", or sometimes just a
the <<def_hash,hash>> of the object.
[[def_object_type]]object type::
One of the identifiers
"<<def_commit,commit>>","<<def_tree,tree>>","<<def_tag,tag>>" or "<<def_blob_object,blob>>"
describing the type of an <<def_object,object>>.
One of the identifiers "<<def_commit_object,commit>>",
"<<def_tree_object,tree>>", "<<def_tag_object,tag>>" or
"<<def_blob_object,blob>>" describing the type of an
<<def_object,object>>.
[[def_octopus]]octopus::
To <<def_merge,merge>> more than two <<def_branch,branches>>. Also denotes an

View File

@@ -1,6 +1,8 @@
<repository>::
The "remote" repository that is the source of a fetch
or pull operation. See the section <<URLS,GIT URLS>> below.
or pull operation. This parameter can be either a URL
(see the section <<URLS,GIT URLS>> below) or the name
of a remote (see the section <<REMOTES,REMOTES>> below).
<refspec>::
The canonical format of a <refspec> parameter is

View File

@@ -13,10 +13,11 @@ include::pretty-options.txt[]
Synonym for `--date=relative`.
--date={relative,local,default,iso,rfc}::
--date={relative,local,default,iso,rfc,short}::
Only takes effect for dates shown in human-readable format, such
as when using "--pretty".
as when using "--pretty". `log.date` config variable sets a default
value for log command's --date option.
+
`--date=relative` shows dates relative to the current time,
e.g. "2 hours ago".
@@ -75,6 +76,16 @@ you would get an output line this:
-xxxxxxx... 1st on a
-----------------------------------------------------------------------
--graph::
Draw a text-based graphical representation of the commit history
on the left hand side of the output. This may cause extra lines
to be printed in between commits, in order for the graph history
to be drawn properly.
+
This implies the '--topo-order' option by default, but the
'--date-order' option may also be specified.
Diff Formatting
~~~~~~~~~~~~~~~

View File

@@ -0,0 +1,179 @@
history graph API
=================
The graph API is used to draw a text-based representation of the commit
history. The API generates the graph in a line-by-line fashion.
Functions
---------
Core functions:
* `graph_init()` creates a new `struct git_graph`
* `graph_release()` destroys a `struct git_graph`, and frees the memory
associated with it.
* `graph_update()` moves the graph to a new commit.
* `graph_next_line()` outputs the next line of the graph into a strbuf. It
does not add a terminating newline.
* `graph_padding_line()` outputs a line of vertical padding in the graph. It
is similar to `graph_next_line()`, but is guaranteed to never print the line
containing the current commit. Where `graph_next_line()` would print the
commit line next, `graph_padding_line()` prints a line that simply extends
all branch lines downwards one row, leaving their positions unchanged.
* `graph_is_commit_finished()` determines if the graph has output all lines
necessary for the current commit. If `graph_update()` is called before all
lines for the current commit have been printed, the next call to
`graph_next_line()` will output an ellipsis, to indicate that a portion of
the graph was omitted.
The following utility functions are wrappers around `graph_next_line()` and
`graph_is_commit_finished()`. They always print the output to stdout.
They can all be called with a NULL graph argument, in which case no graph
output will be printed.
* `graph_show_commit()` calls `graph_next_line()` until it returns non-zero.
This prints all graph lines up to, and including, the line containing this
commit. Output is printed to stdout. The last line printed does not contain
a terminating newline. This should not be called if the commit line has
already been printed, or it will loop forever.
* `graph_show_oneline()` calls `graph_next_line()` and prints the result to
stdout. The line printed does not contain a terminating newline.
* `graph_show_padding()` calls `graph_padding_line()` and prints the result to
stdout. The line printed does not contain a terminating newline.
* `graph_show_remainder()` calls `graph_next_line()` until
`graph_is_commit_finished()` returns non-zero. Output is printed to stdout.
The last line printed does not contain a terminating newline. Returns 1 if
output was printed, and 0 if no output was necessary.
* `graph_show_strbuf()` prints the specified strbuf to stdout, prefixing all
lines but the first with a graph line. The caller is responsible for
ensuring graph output for the first line has already been printed to stdout.
(This can be done with `graph_show_commit()` or `graph_show_oneline()`.) If
a NULL graph is supplied, the strbuf is printed as-is.
* `graph_show_commit_msg()` is similar to `graph_show_strbuf()`, but it also
prints the remainder of the graph, if more lines are needed after the strbuf
ends. It is better than directly calling `graph_show_strbuf()` followed by
`graph_show_remainder()` since it properly handles buffers that do not end in
a terminating newline. The output printed by `graph_show_commit_msg()` will
end in a newline if and only if the strbuf ends in a newline.
Data structure
--------------
`struct git_graph` is an opaque data type used to store the current graph
state.
Calling sequence
----------------
* Create a `struct git_graph` by calling `graph_init()`. When using the
revision walking API, this is done automatically by `setup_revisions()` if
the '--graph' option is supplied.
* Use the revision walking API to walk through a group of contiguous commits.
The `get_revision()` function automatically calls `graph_update()` each time
it is invoked.
* For each commit, call `graph_next_line()` repeatedly, until
`graph_is_commit_finished()` returns non-zero. Each call go
`graph_next_line()` will output a single line of the graph. The resulting
lines will not contain any newlines. `graph_next_line()` returns 1 if the
resulting line contains the current commit, or 0 if this is merely a line
needed to adjust the graph before or after the current commit. This return
value can be used to determine where to print the commit summary information
alongside the graph output.
Limitations
-----------
* `graph_update()` must be called with commits in topological order. It should
not be called on a commit if it has already been invoked with an ancestor of
that commit, or the graph output will be incorrect.
* `graph_update()` must be called on a contiguous group of commits. If
`graph_update()` is called on a particular commit, it should later be called
on all parents of that commit. Parents must not be skipped, or the graph
output will appear incorrect.
+
`graph_update()` may be used on a pruned set of commits only if the parent list
has been rewritten so as to include only ancestors from the pruned set.
* The graph API does not currently support reverse commit ordering. In
order to implement reverse ordering, the graphing API needs an
(efficient) mechanism to find the children of a commit.
Sample usage
------------
------------
struct commit *commit;
struct git_graph *graph = graph_init(opts);
while ((commit = get_revision(opts)) != NULL) {
graph_update(graph, commit);
while (!graph_is_commit_finished(graph))
{
struct strbuf sb;
int is_commit_line;
strbuf_init(&sb, 0);
is_commit_line = graph_next_line(graph, &sb);
fputs(sb.buf, stdout);
if (is_commit_line)
log_tree_commit(opts, commit);
else
putchar(opts->diffopt.line_termination);
}
}
graph_release(graph);
------------
Sample output
-------------
The following is an example of the output from the graph API. This output does
not include any commit summary information--callers are responsible for
outputting that information, if desired.
------------
*
*
M
|\
* |
| | *
| \ \
| \ \
M-. \ \
|\ \ \ \
| | * | |
| | | | | *
| | | | | *
| | | | | M
| | | | | |\
| | | | | | *
| * | | | | |
| | | | | M \
| | | | | |\ |
| | | | * | | |
| | | | * | | |
* | | | | | | |
| |/ / / / / /
|/| / / / / /
* | | | | | |
|/ / / / / /
* | | | | |
| | | | | *
| | | | |/
| | | | *
------------

View File

@@ -1,9 +1,67 @@
revision walking API
====================
The revision walking API offers functions to build a list of revisions
and then iterate over that list.
Calling sequence
----------------
The walking API has a given calling sequence: first you need to
initialize a rev_info structure, then add revisions to control what kind
of revision list do you want to get, finally you can iterate over the
revision list.
Functions
---------
`init_revisions`::
Initialize a rev_info structure with default values. The second
parameter may be NULL or can be prefix path, and then the `.prefix`
variable will be set to it. This is typically the first function you
want to call when you want to deal with a revision list. After calling
this function, you are free to customize options, like set
`.ignore_merges` to 0 if you don't want to ignore merges, and so on. See
`revision.h` for a complete list of available options.
`add_pending_object`::
This function can be used if you want to add commit objects as revision
information. You can use the `UNINTERESTING` object flag to indicate if
you want to include or exclude the given commit (and commits reachable
from the given commit) from the revision list.
+
NOTE: If you have the commits as a string list then you probably want to
use setup_revisions(), instead of parsing each string and using this
function.
`setup_revisions`::
Parse revision information, filling in the `rev_info` structure, and
removing the used arguments from the argument list. Returns the number
of arguments left that weren't recognized, which are also moved to the
head of the argument list. The last parameter is used in case no
parameter given by the first two arguments.
`prepare_revision_walk`::
Prepares the rev_info structure for a walk. You should check if it
returns any error (non-zero return code) and if it does not, you can
start using get_revision() to do the iteration.
`get_revision`::
Takes a pointer to a `rev_info` structure and iterates over it,
returning a `struct commit *` each time you call it. The end of the
revision list is indicated by returning a NULL pointer.
Data structures
---------------
Talk about <revision.h>, things like:
* two diff_options, one for path limiting, another for output;
* calling sequence: init_revisions(), setup_revsions(), get_revision();
* remaining functions;
(Linus, JC, Dscho)

View File

@@ -1,11 +1,46 @@
include::urls.txt[]
REMOTES
-------
REMOTES[[REMOTES]]
------------------
In addition to the above, as a short-hand, the name of a
file in `$GIT_DIR/remotes` directory can be given; the
named file should be in the following format:
The name of one of the following can be used instead
of a URL as `<repository>` argument:
* a remote in the git configuration file: `$GIT_DIR/config`,
* a file in the `$GIT_DIR/remotes` directory, or
* a file in the `$GIT_DIR/branches` directory.
All of these also allow you to omit the refspec from the command line
because they each contain a refspec which git will use by default.
Named remote in configuration file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can choose to provide the name of a remote which you had previously
configured using linkgit:git-remote[1], linkgit:git-config[1]
or even by a manual edit to the `$GIT_DIR/config` file. The URL of
this remote will be used to access the repository. The refspec
of this remote will be used by default when you do
not provide a refspec on the command line. The entry in the
config file would appear like this:
------------
[remote "<name>"]
url = <url>
push = <refspec>
fetch = <refspec>
------------
Named file in `$GIT_DIR/remotes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can choose to provide the name of a
file in `$GIT_DIR/remotes`. The URL
in this file will be used to access the repository. The refspec
in this file will be used as default when you do not
provide a refspec on the command line. This file should have the
following format:
------------
URL: one of the above URL format
@@ -14,42 +49,34 @@ named file should be in the following format:
------------
Then such a short-hand is specified in place of
<repository> without <refspec> parameters on the command
line, <refspec> specified on `Push:` lines or `Pull:`
lines are used for `git-push` and `git-fetch`/`git-pull`,
respectively. Multiple `Push:` and `Pull:` lines may
`Push:` lines are used by `git-push` and
`Pull:` lines are used by `git-pull` and `git-fetch`.
Multiple `Push:` and `Pull:` lines may
be specified for additional branch mappings.
Or, equivalently, in the `$GIT_DIR/config` (note the use
of `fetch` instead of `Pull:`):
Named file in `$GIT_DIR/branches`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can choose to provide the name of a
file in `$GIT_DIR/branches`.
The URL in this file will be used to access the repository.
This file should have the following format:
------------
[remote "<remote>"]
url = <url>
push = <refspec>
fetch = <refspec>
<url>#<head>
------------
The name of a file in `$GIT_DIR/branches` directory can be
specified as an older notation short-hand; the named
file should contain a single line, a URL in one of the
above formats, optionally followed by a hash `#` and the
name of remote head (URL fragment notation).
`$GIT_DIR/branches/<remote>` file that stores a <url>
without the fragment is equivalent to have this in the
corresponding file in the `$GIT_DIR/remotes/` directory.
`<url>` is required; `#<head>` is optional.
When you do not provide a refspec on the command line,
git will use the following refspec, where `<head>` defaults to `master`,
and `<repository>` is the name of this file
you provided in the command line.
------------
URL: <url>
Pull: refs/heads/master:<remote>
refs/heads/<head>:<repository>
------------
while having `<url>#<head>` is equivalent to
------------
URL: <url>
Pull: refs/heads/<head>:<remote>
------------

View File

@@ -1993,7 +1993,7 @@ the right to push to the same repository. In that case, the correct
solution is to retry the push after first updating your work by either a
pull or a fetch followed by a rebase; see the
<<setting-up-a-shared-repository,next section>> and
link:cvs-migration.html[git for CVS users] for more.
linkgit:gitcvs-migration[7][git for CVS users] for more.
[[setting-up-a-shared-repository]]
Setting up a shared repository
@@ -2002,7 +2002,7 @@ Setting up a shared repository
Another way to collaborate is by using a model similar to that
commonly used in CVS, where several developers with special rights
all push to and pull from a single shared repository. See
link:cvs-migration.html[git for CVS users] for instructions on how to
linkgit:gitcvs-migration[7][git for CVS users] for instructions on how to
set this up.
However, while there is nothing wrong with git's support for shared
@@ -4252,7 +4252,10 @@ You see, Git is actually the best tool to find out about the source of Git
itself!
[[glossary]]
include::glossary.txt[]
GIT Glossary
============
include::glossary-content.txt[]
[[git-quick-start]]
Appendix A: Git Quick Reference

View File

@@ -235,7 +235,6 @@ BASIC_LDFLAGS =
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-clone.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-lost-found.sh
SCRIPT_SH += git-merge-octopus.sh
@@ -345,6 +344,7 @@ LIB_H += diff.h
LIB_H += dir.h
LIB_H += fsck.h
LIB_H += git-compat-util.h
LIB_H += graph.h
LIB_H += grep.h
LIB_H += hash.h
LIB_H += list-objects.h
@@ -374,6 +374,7 @@ LIB_H += tree.h
LIB_H += tree-walk.h
LIB_H += unpack-trees.h
LIB_H += utf8.h
LIB_H += wt-status.h
LIB_OBJS += alias.o
LIB_OBJS += alloc.o
@@ -403,6 +404,7 @@ LIB_OBJS += diffcore-order.o
LIB_OBJS += diffcore-pickaxe.o
LIB_OBJS += diffcore-rename.o
LIB_OBJS += diff-delta.o
LIB_OBJS += diff-no-index.o
LIB_OBJS += diff-lib.o
LIB_OBJS += diff.o
LIB_OBJS += dir.o
@@ -410,6 +412,7 @@ LIB_OBJS += entry.o
LIB_OBJS += environment.o
LIB_OBJS += exec_cmd.o
LIB_OBJS += fsck.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
LIB_OBJS += hash.o
LIB_OBJS += help.o
@@ -481,6 +484,7 @@ BUILTIN_OBJS += builtin-check-ref-format.o
BUILTIN_OBJS += builtin-checkout-index.o
BUILTIN_OBJS += builtin-checkout.o
BUILTIN_OBJS += builtin-clean.o
BUILTIN_OBJS += builtin-clone.o
BUILTIN_OBJS += builtin-commit-tree.o
BUILTIN_OBJS += builtin-commit.o
BUILTIN_OBJS += builtin-config.o
@@ -1261,7 +1265,7 @@ remove-dashes:
ifeq ($(firstword $(subst /, ,$(template_dir))),..)
template_instdir = $(gitexecdir)/$(template_dir)
else
template_instdir = $template_dir
template_instdir = $(template_dir)
endif
export template_instdir

View File

@@ -2,7 +2,8 @@
static const char *alias_key;
static char *alias_val;
static int alias_lookup_cb(const char *k, const char *v)
static int alias_lookup_cb(const char *k, const char *v, void *cb)
{
if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
if (!v)
@@ -17,6 +18,6 @@ char *alias_lookup(const char *alias)
{
alias_key = alias;
alias_val = NULL;
git_config(alias_lookup_cb);
git_config(alias_lookup_cb, NULL);
return alias_val;
}

View File

@@ -220,7 +220,7 @@ static void write_global_extended_header(const unsigned char *sha1)
strbuf_release(&ext_header);
}
static int git_tar_config(const char *var, const char *value)
static int git_tar_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "tar.umask")) {
if (value && !strcmp(value, "user")) {
@@ -231,7 +231,7 @@ static int git_tar_config(const char *var, const char *value)
}
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static int write_tar_entry(const unsigned char *sha1,
@@ -268,7 +268,7 @@ int write_tar_archive(struct archiver_args *args)
{
int plen = args->base ? strlen(args->base) : 0;
git_config(git_tar_config);
git_config(git_tar_config, NULL);
archive_time = args->time;
verbose = args->verbose;

View File

@@ -79,12 +79,18 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
prune_directory(dir, pathspec, baselen);
}
struct update_callback_data
{
int flags;
int add_errors;
};
static void update_callback(struct diff_queue_struct *q,
struct diff_options *opt, void *cbdata)
{
int i, verbose;
int i;
struct update_callback_data *data = cbdata;
verbose = *((int *)cbdata);
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
const char *path = p->one->path;
@@ -94,27 +100,36 @@ static void update_callback(struct diff_queue_struct *q,
case DIFF_STATUS_UNMERGED:
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
add_file_to_cache(path, verbose);
if (add_file_to_cache(path, data->flags)) {
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
die("updating files failed");
data->add_errors++;
}
break;
case DIFF_STATUS_DELETED:
remove_file_from_cache(path);
if (verbose)
if (!(data->flags & ADD_CACHE_PRETEND))
remove_file_from_cache(path);
if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
printf("remove '%s'\n", path);
break;
}
}
}
void add_files_to_cache(int verbose, const char *prefix, const char **pathspec)
int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
{
struct update_callback_data data;
struct rev_info rev;
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
rev.prune_data = pathspec;
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &verbose;
data.flags = flags;
data.add_errors = 0;
rev.diffopt.format_callback_data = &data;
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
return !!data.add_errors;
}
static void refresh(int verbose, const char **pathspec)
@@ -177,6 +192,7 @@ static const char ignore_error[] =
"The following paths are ignored by one of your .gitignore files:\n";
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
static int ignore_add_errors;
static struct option builtin_add_options[] = {
OPT__DRY_RUN(&show_only),
@@ -187,14 +203,26 @@ static struct option builtin_add_options[] = {
OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
OPT_END(),
};
static int add_config(const char *var, const char *value, void *cb)
{
if (!strcasecmp(var, "add.ignore-errors")) {
ignore_add_errors = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value, cb);
}
int cmd_add(int argc, const char **argv, const char *prefix)
{
int exit_status = 0;
int i, newfd;
const char **pathspec;
struct dir_struct dir;
int flags;
argc = parse_options(argc, argv, builtin_add_options,
builtin_add_usage, 0);
@@ -203,16 +231,20 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (add_interactive)
exit(interactive_add(argc, argv, prefix));
git_config(git_default_config);
git_config(add_config, NULL);
newfd = hold_locked_index(&lock_file, 1);
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0));
if (take_worktree_changes) {
const char **pathspec;
if (read_cache() < 0)
die("index file corrupt");
pathspec = get_pathspec(prefix, argv);
add_files_to_cache(verbose, prefix, pathspec);
exit_status = add_files_to_cache(prefix, pathspec, flags);
goto finish;
}
@@ -230,17 +262,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
fill_directory(&dir, pathspec, ignored_too);
if (show_only) {
const char *sep = "", *eof = "";
for (i = 0; i < dir.nr; i++) {
printf("%s%s", sep, dir.entries[i]->name);
sep = " ";
eof = "\n";
}
fputs(eof, stdout);
return 0;
}
if (read_cache() < 0)
die("index file corrupt");
@@ -254,7 +275,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
for (i = 0; i < dir.nr; i++)
add_file_to_cache(dir.entries[i]->name, verbose);
if (add_file_to_cache(dir.entries[i]->name, flags)) {
if (!ignore_add_errors)
die("adding files failed");
exit_status = 1;
}
finish:
if (active_cache_changed) {
@@ -263,5 +288,5 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die("Unable to write new index file");
}
return 0;
return exit_status;
}

View File

@@ -418,7 +418,7 @@ static int guess_p_value(const char *nameline)
}
/*
* Get the name etc info from the --/+++ lines of a traditional patch header
* Get the name etc info from the ---/+++ lines of a traditional patch header
*
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
* files, we can happily check the index for a match, but for creating a
@@ -1143,21 +1143,6 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
if (patch->is_delete < 0 &&
(newlines || (patch->fragments && patch->fragments->next)))
patch->is_delete = 0;
if (!unidiff_zero || context) {
/* If the user says the patch is not generated with
* --unified=0, or if we have seen context lines,
* then not having oldlines means the patch is creation,
* and not having newlines means the patch is deletion.
*/
if (patch->is_new < 0 && !oldlines) {
patch->is_new = 1;
patch->old_name = NULL;
}
if (patch->is_delete < 0 && !newlines) {
patch->is_delete = 1;
patch->new_name = NULL;
}
}
if (0 < patch->is_new && oldlines)
die("new file %s depends on old contents", patch->new_name);
@@ -2267,6 +2252,79 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
}
static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
{
const char *old_name = patch->old_name;
int stat_ret = 0;
unsigned st_mode = 0;
/*
* Make sure that we do not have local modifications from the
* index when we are looking at the index. Also make sure
* we have the preimage file to be patched in the work tree,
* unless --cached, which tells git to apply only in the index.
*/
if (!old_name)
return 0;
assert(patch->is_new <= 0);
if (!cached) {
stat_ret = lstat(old_name, st);
if (stat_ret && errno != ENOENT)
return error("%s: %s", old_name, strerror(errno));
}
if (check_index) {
int pos = cache_name_pos(old_name, strlen(old_name));
if (pos < 0) {
if (patch->is_new < 0)
goto is_new;
return error("%s: does not exist in index", old_name);
}
*ce = active_cache[pos];
if (stat_ret < 0) {
struct checkout costate;
/* checkout */
costate.base_dir = "";
costate.base_dir_len = 0;
costate.force = 0;
costate.quiet = 0;
costate.not_new = 0;
costate.refresh_cache = 1;
if (checkout_entry(*ce, &costate, NULL) ||
lstat(old_name, st))
return -1;
}
if (!cached && verify_index_match(*ce, st))
return error("%s: does not match index", old_name);
if (cached)
st_mode = (*ce)->ce_mode;
} else if (stat_ret < 0) {
if (patch->is_new < 0)
goto is_new;
return error("%s: %s", old_name, strerror(errno));
}
if (!cached)
st_mode = ce_mode_from_stat(*ce, st->st_mode);
if (patch->is_new < 0)
patch->is_new = 0;
if (!patch->old_mode)
patch->old_mode = st_mode;
if ((st_mode ^ patch->old_mode) & S_IFMT)
return error("%s: wrong type", old_name);
if (st_mode != patch->old_mode)
fprintf(stderr, "warning: %s has type %o, expected %o\n",
old_name, st_mode, patch->old_mode);
return 0;
is_new:
patch->is_new = 1;
patch->is_delete = 0;
patch->old_name = NULL;
return 0;
}
static int check_patch(struct patch *patch, struct patch *prev_patch)
{
struct stat st;
@@ -2275,66 +2333,14 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
const char *name = old_name ? old_name : new_name;
struct cache_entry *ce = NULL;
int ok_if_exists;
int status;
patch->rejected = 1; /* we will drop this after we succeed */
/*
* Make sure that we do not have local modifications from the
* index when we are looking at the index. Also make sure
* we have the preimage file to be patched in the work tree,
* unless --cached, which tells git to apply only in the index.
*/
if (old_name) {
int stat_ret = 0;
unsigned st_mode = 0;
if (!cached)
stat_ret = lstat(old_name, &st);
if (check_index) {
int pos = cache_name_pos(old_name, strlen(old_name));
if (pos < 0)
return error("%s: does not exist in index",
old_name);
ce = active_cache[pos];
if (stat_ret < 0) {
struct checkout costate;
if (errno != ENOENT)
return error("%s: %s", old_name,
strerror(errno));
/* checkout */
costate.base_dir = "";
costate.base_dir_len = 0;
costate.force = 0;
costate.quiet = 0;
costate.not_new = 0;
costate.refresh_cache = 1;
if (checkout_entry(ce,
&costate,
NULL) ||
lstat(old_name, &st))
return -1;
}
if (!cached && verify_index_match(ce, &st))
return error("%s: does not match index",
old_name);
if (cached)
st_mode = ce->ce_mode;
} else if (stat_ret < 0)
return error("%s: %s", old_name, strerror(errno));
if (!cached)
st_mode = ce_mode_from_stat(ce, st.st_mode);
if (patch->is_new < 0)
patch->is_new = 0;
if (!patch->old_mode)
patch->old_mode = st_mode;
if ((st_mode ^ patch->old_mode) & S_IFMT)
return error("%s: wrong type", old_name);
if (st_mode != patch->old_mode)
fprintf(stderr, "warning: %s has type %o, expected %o\n",
old_name, st_mode, patch->old_mode);
}
status = check_preimage(patch, &ce, &st);
if (status)
return status;
old_name = patch->old_name;
if (new_name && prev_patch && 0 < prev_patch->is_delete &&
!strcmp(prev_patch->old_name, new_name))
@@ -2979,11 +2985,11 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
return 0;
}
static int git_apply_config(const char *var, const char *value)
static int git_apply_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "apply.whitespace"))
return git_config_string(&apply_default_whitespace, var, value);
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
@@ -2999,7 +3005,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
prefix = setup_git_directory_gently(&is_not_gitdir);
prefix_length = prefix ? strlen(prefix) : 0;
git_config(git_apply_config);
git_config(git_apply_config, NULL);
if (apply_default_whitespace)
parse_whitespace_option(apply_default_whitespace);

View File

@@ -1993,7 +1993,7 @@ static void prepare_blame_range(struct scoreboard *sb,
usage(blame_usage);
}
static int git_blame_config(const char *var, const char *value)
static int git_blame_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "blame.showroot")) {
show_root = git_config_bool(var, value);
@@ -2003,7 +2003,7 @@ static int git_blame_config(const char *var, const char *value)
blank_boundary = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static struct commit *fake_working_tree_commit(const char *path, const char *contents_from)
@@ -2141,7 +2141,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
cmd_is_annotate = !strcmp(argv[0], "annotate");
git_config(git_blame_config);
git_config(git_blame_config, NULL);
save_commit_buffer = 0;
opt = 0;

View File

@@ -63,7 +63,7 @@ static int parse_branch_color_slot(const char *var, int ofs)
die("bad config variable '%s'", var);
}
static int git_branch_config(const char *var, const char *value)
static int git_branch_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "color.branch")) {
branch_use_color = git_config_colorbool(var, value, -1);
@@ -76,7 +76,7 @@ static int git_branch_config(const char *var, const char *value)
color_parse(value, var, branch_colors[slot]);
return 0;
}
return git_color_default_config(var, value);
return git_color_default_config(var, value, cb);
}
static const char *branch_get_color(enum color_branch ix)
@@ -461,7 +461,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_END(),
};
git_config(git_branch_config);
git_config(git_branch_config, NULL);
if (branch_use_color == -1)
branch_use_color = git_use_color_default;

View File

@@ -8,6 +8,10 @@
#include "tag.h"
#include "tree.h"
#include "builtin.h"
#include "parse-options.h"
#define BATCH 1
#define BATCH_CHECK 2
static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
{
@@ -76,31 +80,16 @@ static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
write_or_die(1, cp, endp - cp);
}
int cmd_cat_file(int argc, const char **argv, const char *prefix)
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
{
unsigned char sha1[20];
enum object_type type;
void *buf;
unsigned long size;
int opt;
const char *exp_type, *obj_name;
git_config(git_default_config);
if (argc != 3)
usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>");
exp_type = argv[1];
obj_name = argv[2];
if (get_sha1(obj_name, sha1))
die("Not a valid object name %s", obj_name);
opt = 0;
if ( exp_type[0] == '-' ) {
opt = exp_type[1];
if ( !opt || exp_type[2] )
opt = -1; /* Not a single character option */
}
buf = NULL;
switch (opt) {
case 't':
@@ -157,3 +146,108 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
write_or_die(1, buf, size);
return 0;
}
static int batch_one_object(const char *obj_name, int print_contents)
{
unsigned char sha1[20];
enum object_type type;
unsigned long size;
void *contents = contents;
if (!obj_name)
return 1;
if (get_sha1(obj_name, sha1)) {
printf("%s missing\n", obj_name);
return 0;
}
if (print_contents == BATCH)
contents = read_sha1_file(sha1, &type, &size);
else
type = sha1_object_info(sha1, &size);
if (type <= 0)
return 1;
printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size);
fflush(stdout);
if (print_contents == BATCH) {
write_or_die(1, contents, size);
printf("\n");
fflush(stdout);
}
return 0;
}
static int batch_objects(int print_contents)
{
struct strbuf buf;
strbuf_init(&buf, 0);
while (strbuf_getline(&buf, stdin, '\n') != EOF) {
int error = batch_one_object(buf.buf, print_contents);
if (error)
return error;
}
return 0;
}
static const char * const cat_file_usage[] = {
"git-cat-file [-t|-s|-e|-p|<type>] <sha1>",
"git-cat-file [--batch|--batch-check] < <list_of_sha1s>",
NULL
};
int cmd_cat_file(int argc, const char **argv, const char *prefix)
{
int opt = 0, batch = 0;
const char *exp_type = NULL, *obj_name = NULL;
const struct option options[] = {
OPT_GROUP("<type> can be one of: blob, tree, commit, tag"),
OPT_SET_INT('t', NULL, &opt, "show object type", 't'),
OPT_SET_INT('s', NULL, &opt, "show object size", 's'),
OPT_SET_INT('e', NULL, &opt,
"exit with zero when there's no error", 'e'),
OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
OPT_SET_INT(0, "batch", &batch,
"show info and content of objects feeded on stdin", BATCH),
OPT_SET_INT(0, "batch-check", &batch,
"show info about objects feeded on stdin",
BATCH_CHECK),
OPT_END()
};
git_config(git_default_config, NULL);
if (argc != 3 && argc != 2)
usage_with_options(cat_file_usage, options);
argc = parse_options(argc, argv, options, cat_file_usage, 0);
if (opt) {
if (argc == 1)
obj_name = argv[0];
else
usage_with_options(cat_file_usage, options);
}
if (!opt && !batch) {
if (argc == 2) {
exp_type = argv[0];
obj_name = argv[1];
} else
usage_with_options(cat_file_usage, options);
}
if (batch && (opt || argc)) {
usage_with_options(cat_file_usage, options);
}
if (batch)
return batch_objects(batch);
return cat_one_file(opt, exp_type, obj_name);
}

View File

@@ -166,7 +166,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
int read_from_stdin = 0;
int prefix_length;
git_config(git_default_config);
git_config(git_default_config, NULL);
state.base_dir = "";
prefix_length = prefix ? strlen(prefix) : 0;

View File

@@ -84,6 +84,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
unsigned char rev[20];
int flag;
struct commit *head;
int errs = 0;
int newfd;
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -106,13 +107,14 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
if (report_path_error(ps_matched, pathspec, 0))
return 1;
/* Now we are committed to check them out */
memset(&state, 0, sizeof(state));
state.force = 1;
state.refresh_cache = 1;
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
if (pathspec_match(pathspec, NULL, ce->name, 0)) {
checkout_entry(ce, &state, NULL);
errs |= checkout_entry(ce, &state, NULL);
}
}
@@ -123,7 +125,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
resolve_ref("HEAD", rev, 0, &flag);
head = lookup_commit_reference_gently(rev, 1);
return post_checkout_hook(head, head, 0);
errs |= post_checkout_hook(head, head, 0);
return errs;
}
static void show_local_changes(struct object *head)
@@ -148,57 +151,50 @@ static void describe_detached_head(char *msg, struct commit *commit)
strbuf_release(&sb);
}
static int reset_to_new(struct tree *tree, int quiet)
{
struct unpack_trees_options opts;
struct tree_desc tree_desc;
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
opts.update = 1;
opts.reset = 1;
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = !quiet;
opts.src_index = &the_index;
opts.dst_index = &the_index;
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
if (unpack_trees(1, &tree_desc, &opts))
return 128;
return 0;
}
static void reset_clean_to_new(struct tree *tree, int quiet)
{
struct unpack_trees_options opts;
struct tree_desc tree_desc;
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
opts.skip_unmerged = 1;
opts.reset = 1;
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = !quiet;
opts.src_index = &the_index;
opts.dst_index = &the_index;
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
if (unpack_trees(1, &tree_desc, &opts))
exit(128);
}
struct checkout_opts {
int quiet;
int merge;
int force;
int writeout_error;
char *new_branch;
int new_branch_log;
enum branch_track track;
};
static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
{
struct unpack_trees_options opts;
struct tree_desc tree_desc;
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
opts.update = worktree;
opts.skip_unmerged = !worktree;
opts.reset = 1;
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = !o->quiet;
opts.src_index = &the_index;
opts.dst_index = &the_index;
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
switch (unpack_trees(1, &tree_desc, &opts)) {
case -2:
o->writeout_error = 1;
/*
* We return 0 nevertheless, as the index is all right
* and more importantly we have made best efforts to
* update paths in the work tree, and we cannot revert
* them.
*/
case 0:
return 0;
default:
return 128;
}
}
struct branch_info {
const char *name; /* The short name used */
const char *path; /* The full name of a real branch */
@@ -223,7 +219,7 @@ static int merge_working_tree(struct checkout_opts *opts,
read_cache();
if (opts->force) {
ret = reset_to_new(new->commit->tree, opts->quiet);
ret = reset_tree(new->commit->tree, opts, 1);
if (ret)
return ret;
} else {
@@ -236,6 +232,8 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.src_index = &the_index;
topts.dst_index = &the_index;
topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
refresh_cache(REFRESH_QUIET);
if (unmerged_cache()) {
@@ -257,7 +255,8 @@ static int merge_working_tree(struct checkout_opts *opts,
tree = parse_tree_indirect(new->commit->object.sha1);
init_tree_desc(&trees[1], tree->buffer, tree->size);
if (unpack_trees(2, trees, &topts)) {
ret = unpack_trees(2, trees, &topts);
if (ret == -1) {
/*
* Unpack couldn't do a trivial merge; either
* give up or do a real merge, depending on
@@ -282,15 +281,17 @@ static int merge_working_tree(struct checkout_opts *opts,
* entries in the index.
*/
add_files_to_cache(0, NULL, NULL);
add_files_to_cache(NULL, NULL, 0);
work = write_tree_from_memory();
ret = reset_to_new(new->commit->tree, opts->quiet);
ret = reset_tree(new->commit->tree, opts, 1);
if (ret)
return ret;
merge_trees(new->commit->tree, work, old->commit->tree,
new->name, "local", &result);
reset_clean_to_new(new->commit->tree, opts->quiet);
ret = reset_tree(new->commit->tree, opts, 0);
if (ret)
return ret;
}
}
@@ -490,7 +491,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
update_refs_for_switch(opts, &old, new);
return post_checkout_hook(old.commit, new->commit, 1);
ret = post_checkout_hook(old.commit, new->commit, 1);
return ret || opts->writeout_error;
}
int cmd_checkout(int argc, const char **argv, const char *prefix)
@@ -514,7 +516,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
memset(&new, 0, sizeof(new));
git_config(git_default_config);
git_config(git_default_config, NULL);
opts.track = git_branch_track;

View File

@@ -19,11 +19,11 @@ static const char *const builtin_clean_usage[] = {
NULL
};
static int git_clean_config(const char *var, const char *value)
static int git_clean_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "clean.requireforce"))
force = !git_config_bool(var, value);
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
int cmd_clean(int argc, const char **argv, const char *prefix)
@@ -50,7 +50,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
OPT_END()
};
git_config(git_clean_config);
git_config(git_clean_config, NULL);
if (force < 0)
force = 0;
else

553
builtin-clone.c Normal file
View File

@@ -0,0 +1,553 @@
/*
* Builtin "git clone"
*
* Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,
* 2008 Daniel Barkalow <barkalow@iabervon.org>
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
*
* Clone a repository into a different directory that does not yet exist.
*/
#include "cache.h"
#include "parse-options.h"
#include "fetch-pack.h"
#include "refs.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
#include "transport.h"
#include "strbuf.h"
#include "dir.h"
/*
* Overall FIXMEs:
* - respect DB_ENVIRONMENT for .git/objects.
*
* Implementation notes:
* - dropping use-separate-remote and no-separate-remote compatibility
*
*/
static const char * const builtin_clone_usage[] = {
"git-clone [options] [--] <repo> [<dir>]",
NULL
};
static int option_quiet, option_no_checkout, option_bare;
static int option_local, option_no_hardlinks, option_shared;
static char *option_template, *option_reference, *option_depth;
static char *option_origin = NULL;
static char *option_upload_pack = "git-upload-pack";
static struct option builtin_clone_options[] = {
OPT__QUIET(&option_quiet),
OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
"don't create a checkout"),
OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
OPT_BOOLEAN('l', "local", &option_local,
"to clone from a local repository"),
OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
"don't use local hardlinks, always copy"),
OPT_BOOLEAN('s', "shared", &option_shared,
"setup as shared repository"),
OPT_STRING(0, "template", &option_template, "path",
"path the template repository"),
OPT_STRING(0, "reference", &option_reference, "repo",
"reference repository"),
OPT_STRING('o', "origin", &option_origin, "branch",
"use <branch> instead or 'origin' to track upstream"),
OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
"path to git-upload-pack on the remote"),
OPT_STRING(0, "depth", &option_depth, "depth",
"create a shallow clone of that depth"),
OPT_END()
};
static char *get_repo_path(const char *repo, int *is_bundle)
{
static char *suffix[] = { "/.git", ".git", "" };
static char *bundle_suffix[] = { ".bundle", "" };
struct stat st;
int i;
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
const char *path;
path = mkpath("%s%s", repo, suffix[i]);
if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
*is_bundle = 0;
return xstrdup(make_absolute_path(path));
}
}
for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
const char *path;
path = mkpath("%s%s", repo, bundle_suffix[i]);
if (!stat(path, &st) && S_ISREG(st.st_mode)) {
*is_bundle = 1;
return xstrdup(make_absolute_path(path));
}
}
return NULL;
}
static char *guess_dir_name(const char *repo, int is_bundle)
{
const char *p, *start, *end, *limit;
int after_slash_or_colon;
/* Guess dir name from repository: strip trailing '/',
* strip trailing '[:/]*.{git,bundle}', strip leading '.*[/:]'. */
after_slash_or_colon = 1;
limit = repo + strlen(repo);
start = repo;
end = limit;
for (p = repo; p < limit; p++) {
const char *prefix = is_bundle ? ".bundle" : ".git";
if (!prefixcmp(p, prefix)) {
if (!after_slash_or_colon)
end = p;
p += strlen(prefix) - 1;
} else if (!prefixcmp(p, ".bundle")) {
if (!after_slash_or_colon)
end = p;
p += 7;
} else if (*p == '/' || *p == ':') {
if (end == limit)
end = p;
after_slash_or_colon = 1;
} else if (after_slash_or_colon) {
start = p;
end = limit;
after_slash_or_colon = 0;
}
}
return xstrndup(start, end - start);
}
static int is_directory(const char *path)
{
struct stat buf;
return !stat(path, &buf) && S_ISDIR(buf.st_mode);
}
static void setup_reference(const char *repo)
{
const char *ref_git;
char *ref_git_copy;
struct remote *remote;
struct transport *transport;
const struct ref *extra;
ref_git = make_absolute_path(option_reference);
if (is_directory(mkpath("%s/.git/objects", ref_git)))
ref_git = mkpath("%s/.git", ref_git);
else if (!is_directory(mkpath("%s/objects", ref_git)))
die("reference repository '%s' is not a local directory.",
option_reference);
ref_git_copy = xstrdup(ref_git);
add_to_alternates_file(ref_git_copy);
remote = remote_get(ref_git_copy);
transport = transport_get(remote, ref_git_copy);
for (extra = transport_get_remote_refs(transport); extra;
extra = extra->next)
add_extra_ref(extra->name, extra->old_sha1, 0);
transport_disconnect(transport);
free(ref_git_copy);
}
static void copy_or_link_directory(char *src, char *dest)
{
struct dirent *de;
struct stat buf;
int src_len, dest_len;
DIR *dir;
dir = opendir(src);
if (!dir)
die("failed to open %s\n", src);
if (mkdir(dest, 0777)) {
if (errno != EEXIST)
die("failed to create directory %s\n", dest);
else if (stat(dest, &buf))
die("failed to stat %s\n", dest);
else if (!S_ISDIR(buf.st_mode))
die("%s exists and is not a directory\n", dest);
}
src_len = strlen(src);
src[src_len] = '/';
dest_len = strlen(dest);
dest[dest_len] = '/';
while ((de = readdir(dir)) != NULL) {
strcpy(src + src_len + 1, de->d_name);
strcpy(dest + dest_len + 1, de->d_name);
if (stat(src, &buf)) {
warning ("failed to stat %s\n", src);
continue;
}
if (S_ISDIR(buf.st_mode)) {
if (de->d_name[0] != '.')
copy_or_link_directory(src, dest);
continue;
}
if (unlink(dest) && errno != ENOENT)
die("failed to unlink %s\n", dest);
if (!option_no_hardlinks) {
if (!link(src, dest))
continue;
if (option_local)
die("failed to create link %s\n", dest);
option_no_hardlinks = 1;
}
if (copy_file(dest, src, 0666))
die("failed to copy file to %s\n", dest);
}
closedir(dir);
}
static const struct ref *clone_local(const char *src_repo,
const char *dest_repo)
{
const struct ref *ret;
char src[PATH_MAX];
char dest[PATH_MAX];
struct remote *remote;
struct transport *transport;
if (option_shared)
add_to_alternates_file(src_repo);
else {
snprintf(src, PATH_MAX, "%s/objects", src_repo);
snprintf(dest, PATH_MAX, "%s/objects", dest_repo);
copy_or_link_directory(src, dest);
}
remote = remote_get(src_repo);
transport = transport_get(remote, src_repo);
ret = transport_get_remote_refs(transport);
transport_disconnect(transport);
return ret;
}
static const char *junk_work_tree;
static const char *junk_git_dir;
pid_t junk_pid;
static void remove_junk(void)
{
struct strbuf sb;
if (getpid() != junk_pid)
return;
strbuf_init(&sb, 0);
if (junk_git_dir) {
strbuf_addstr(&sb, junk_git_dir);
remove_dir_recursively(&sb, 0);
strbuf_reset(&sb);
}
if (junk_work_tree) {
strbuf_addstr(&sb, junk_work_tree);
remove_dir_recursively(&sb, 0);
strbuf_reset(&sb);
}
}
static void remove_junk_on_signal(int signo)
{
remove_junk();
signal(SIGINT, SIG_DFL);
raise(signo);
}
static const struct ref *locate_head(const struct ref *refs,
const struct ref *mapped_refs,
const struct ref **remote_head_p)
{
const struct ref *remote_head = NULL;
const struct ref *remote_master = NULL;
const struct ref *r;
for (r = refs; r; r = r->next)
if (!strcmp(r->name, "HEAD"))
remote_head = r;
for (r = mapped_refs; r; r = r->next)
if (!strcmp(r->name, "refs/heads/master"))
remote_master = r;
if (remote_head_p)
*remote_head_p = remote_head;
/* If there's no HEAD value at all, never mind. */
if (!remote_head)
return NULL;
/* If refs/heads/master could be right, it is. */
if (remote_master && !hashcmp(remote_master->old_sha1,
remote_head->old_sha1))
return remote_master;
/* Look for another ref that points there */
for (r = mapped_refs; r; r = r->next)
if (r != remote_head &&
!hashcmp(r->old_sha1, remote_head->old_sha1))
return r;
/* Nothing is the same */
return NULL;
}
static struct ref *write_remote_refs(const struct ref *refs,
struct refspec *refspec, const char *reflog)
{
struct ref *local_refs = NULL;
struct ref **tail = &local_refs;
struct ref *r;
get_fetch_map(refs, refspec, &tail, 0);
get_fetch_map(refs, tag_refspec, &tail, 0);
for (r = local_refs; r; r = r->next)
update_ref(reflog,
r->peer_ref->name, r->old_sha1, NULL, 0, DIE_ON_ERR);
return local_refs;
}
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int use_local_hardlinks = 1;
int use_separate_remote = 1;
int is_bundle = 0;
struct stat buf;
const char *repo_name, *repo, *work_tree, *git_dir;
char *path, *dir;
const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
char branch_top[256], key[256], value[256];
struct strbuf reflog_msg;
struct refspec refspec;
junk_pid = getpid();
argc = parse_options(argc, argv, builtin_clone_options,
builtin_clone_usage, 0);
if (argc == 0)
die("You must specify a repository to clone.");
if (option_no_hardlinks)
use_local_hardlinks = 0;
if (option_bare) {
if (option_origin)
die("--bare and --origin %s options are incompatible.",
option_origin);
option_no_checkout = 1;
use_separate_remote = 0;
}
if (!option_origin)
option_origin = "origin";
repo_name = argv[0];
path = get_repo_path(repo_name, &is_bundle);
if (path)
repo = path;
else if (!strchr(repo_name, ':'))
repo = xstrdup(make_absolute_path(repo_name));
else
repo = repo_name;
if (argc == 2)
dir = xstrdup(argv[1]);
else
dir = guess_dir_name(repo_name, is_bundle);
if (!stat(dir, &buf))
die("destination directory '%s' already exists.", dir);
strbuf_init(&reflog_msg, 0);
strbuf_addf(&reflog_msg, "clone: from %s", repo);
if (option_bare)
work_tree = NULL;
else {
work_tree = getenv("GIT_WORK_TREE");
if (work_tree && !stat(work_tree, &buf))
die("working tree '%s' already exists.", work_tree);
}
if (option_bare || work_tree)
git_dir = xstrdup(dir);
else {
work_tree = dir;
git_dir = xstrdup(mkpath("%s/.git", dir));
}
if (!option_bare) {
junk_work_tree = work_tree;
if (mkdir(work_tree, 0755))
die("could not create work tree dir '%s'.", work_tree);
set_git_work_tree(work_tree);
}
junk_git_dir = git_dir;
atexit(remove_junk);
signal(SIGINT, remove_junk_on_signal);
setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
set_git_dir(make_absolute_path(git_dir));
fprintf(stderr, "Initialize %s\n", git_dir);
init_db(option_template, option_quiet ? INIT_DB_QUIET : 0);
if (option_reference)
setup_reference(git_dir);
git_config(git_default_config, NULL);
if (option_bare) {
strcpy(branch_top, "refs/heads/");
git_config_set("core.bare", "true");
} else {
snprintf(branch_top, sizeof(branch_top),
"refs/remotes/%s/", option_origin);
/* Configure the remote */
snprintf(key, sizeof(key), "remote.%s.url", option_origin);
git_config_set(key, repo);
snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
snprintf(value, sizeof(value),
"+refs/heads/*:%s*", branch_top);
git_config_set_multivar(key, value, "^$", 0);
}
refspec.force = 0;
refspec.pattern = 1;
refspec.src = "refs/heads/";
refspec.dst = branch_top;
if (path && !is_bundle)
refs = clone_local(path, git_dir);
else {
struct remote *remote = remote_get(argv[0]);
struct transport *transport = transport_get(remote, argv[0]);
if (!transport->get_refs_list || !transport->fetch)
die("Don't know how to clone %s", transport->url);
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
if (option_depth)
transport_set_option(transport, TRANS_OPT_DEPTH,
option_depth);
if (option_quiet)
transport->verbose = -1;
refs = transport_get_remote_refs(transport);
transport_fetch_refs(transport, refs);
}
clear_extra_refs();
mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
head_points_at = locate_head(refs, mapped_refs, &remote_head);
if (head_points_at) {
/* Local default branch link */
create_symref("HEAD", head_points_at->name, NULL);
if (!option_bare) {
struct strbuf head_ref;
const char *head = head_points_at->name;
if (!prefixcmp(head, "refs/heads/"))
head += 11;
/* Set up the initial local branch */
/* Local branch initial value */
update_ref(reflog_msg.buf, "HEAD",
head_points_at->old_sha1,
NULL, 0, DIE_ON_ERR);
strbuf_init(&head_ref, 0);
strbuf_addstr(&head_ref, branch_top);
strbuf_addstr(&head_ref, "HEAD");
/* Remote branch link */
create_symref(head_ref.buf,
head_points_at->peer_ref->name,
reflog_msg.buf);
snprintf(key, sizeof(key), "branch.%s.remote", head);
git_config_set(key, option_origin);
snprintf(key, sizeof(key), "branch.%s.merge", head);
git_config_set(key, head_points_at->name);
}
} else if (remote_head) {
/* Source had detached HEAD pointing somewhere. */
if (!option_bare)
update_ref(reflog_msg.buf, "HEAD",
remote_head->old_sha1,
NULL, REF_NODEREF, DIE_ON_ERR);
} else {
/* Nothing to checkout out */
if (!option_no_checkout)
warning("remote HEAD refers to nonexistent ref, "
"unable to checkout.\n");
option_no_checkout = 1;
}
if (!option_no_checkout) {
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
struct unpack_trees_options opts;
struct tree *tree;
struct tree_desc t;
int fd;
/* We need to be in the new work tree for the checkout */
setup_work_tree();
fd = hold_locked_index(lock_file, 1);
memset(&opts, 0, sizeof opts);
opts.update = 1;
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = !option_quiet;
opts.src_index = &the_index;
opts.dst_index = &the_index;
tree = parse_tree_indirect(remote_head->old_sha1);
parse_tree(tree);
init_tree_desc(&t, tree->buffer, tree->size);
unpack_trees(1, &t, &opts);
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(lock_file))
die("unable to write new index file");
}
strbuf_release(&reflog_msg);
junk_pid = 0;
return 0;
}

View File

@@ -60,7 +60,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
struct strbuf buffer;
int encoding_is_utf8;
git_config(git_default_config);
git_config(git_default_config, NULL);
if (argc < 2)
usage(commit_tree_usage);

View File

@@ -179,9 +179,10 @@ static void add_remove_files(struct path_list *list)
struct stat st;
struct path_list_item *p = &(list->items[i]);
if (!lstat(p->path, &st))
add_to_cache(p->path, &st, 0);
else
if (!lstat(p->path, &st)) {
if (add_to_cache(p->path, &st, 0))
die("updating files failed");
} else
remove_file_from_cache(p->path);
}
}
@@ -222,6 +223,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
if (interactive) {
interactive_add(argc, argv, prefix);
if (read_cache() < 0)
die("index file corrupt");
commit_style = COMMIT_AS_IS;
return get_index_file();
}
@@ -246,7 +249,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
*/
if (all || (also && pathspec && *pathspec)) {
int fd = hold_locked_index(&index_lock, 1);
add_files_to_cache(0, also ? prefix : NULL, pathspec);
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
refresh_cache(REFRESH_QUIET);
if (write_cache(fd, active_cache, active_nr) ||
close_lock_file(&index_lock))
@@ -805,7 +808,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
const char *index_file;
int commitable;
git_config(git_status_config);
git_config(git_status_config, NULL);
if (wt_status_use_color == -1)
wt_status_use_color = git_use_color_default;
@@ -859,7 +862,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
}
}
int git_commit_config(const char *k, const char *v)
int git_commit_config(const char *k, const char *v, void *cb)
{
if (!strcmp(k, "commit.template")) {
if (!v)
@@ -868,7 +871,7 @@ int git_commit_config(const char *k, const char *v)
return 0;
}
return git_status_config(k, v);
return git_status_config(k, v, cb);
}
static const char commit_utf8_warn[] =
@@ -880,10 +883,19 @@ static void add_parent(struct strbuf *sb, const unsigned char *sha1)
{
struct object *obj = parse_object(sha1);
const char *parent = sha1_to_hex(sha1);
const char *cp;
if (!obj)
die("Unable to find commit parent %s", parent);
if (obj->type != OBJ_COMMIT)
die("Parent %s isn't a proper commit", parent);
for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) {
if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') {
error("duplicate parent %s ignored", parent);
return;
}
}
strbuf_addf(sb, "parent %s\n", parent);
}
@@ -896,7 +908,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
unsigned char commit_sha1[20];
struct ref_lock *ref_lock;
git_config(git_commit_config);
git_config(git_commit_config, NULL);
argc = parse_and_validate_options(argc, argv, builtin_commit_usage);

View File

@@ -18,7 +18,7 @@ static char key_delim = ' ';
static char term = '\n';
static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
static int show_all_config(const char *key_, const char *value_)
static int show_all_config(const char *key_, const char *value_, void *cb)
{
if (value_)
printf("%s%c%s%c", key_, delim, value_, term);
@@ -27,7 +27,7 @@ static int show_all_config(const char *key_, const char *value_)
return 0;
}
static int show_config(const char* key_, const char* value_)
static int show_config(const char* key_, const char* value_, void *cb)
{
char value[256];
const char *vptr = value;
@@ -121,14 +121,14 @@ static int get_value(const char* key_, const char* regex_)
}
if (do_all && system_wide)
git_config_from_file(show_config, system_wide);
git_config_from_file(show_config, system_wide, NULL);
if (do_all && global)
git_config_from_file(show_config, global);
git_config_from_file(show_config, local);
git_config_from_file(show_config, global, NULL);
git_config_from_file(show_config, local, NULL);
if (!do_all && !seen && global)
git_config_from_file(show_config, global);
git_config_from_file(show_config, global, NULL);
if (!do_all && !seen && system_wide)
git_config_from_file(show_config, system_wide);
git_config_from_file(show_config, system_wide, NULL);
free(key);
if (regexp) {
@@ -182,7 +182,7 @@ static int get_color_found;
static const char *get_color_slot;
static char parsed_color[COLOR_MAXLEN];
static int git_get_color_config(const char *var, const char *value)
static int git_get_color_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, get_color_slot)) {
if (!value)
@@ -218,7 +218,7 @@ static int get_color(int argc, const char **argv)
get_color_found = 0;
parsed_color[0] = '\0';
git_config(git_get_color_config);
git_config(git_get_color_config, NULL);
if (!get_color_found && def_color)
color_parse(def_color, "command line", parsed_color);
@@ -230,7 +230,8 @@ static int get_color(int argc, const char **argv)
static int stdout_is_tty;
static int get_colorbool_found;
static int get_diff_color_found;
static int git_get_colorbool_config(const char *var, const char *value)
static int git_get_colorbool_config(const char *var, const char *value,
void *cb)
{
if (!strcmp(var, get_color_slot)) {
get_colorbool_found =
@@ -265,7 +266,7 @@ static int get_colorbool(int argc, const char **argv)
get_colorbool_found = -1;
get_diff_color_found = -1;
get_color_slot = argv[0];
git_config(git_get_colorbool_config);
git_config(git_get_colorbool_config, NULL);
if (get_colorbool_found < 0) {
if (!strcmp(get_color_slot, "color.diff"))
@@ -298,7 +299,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
if (argc != 2)
usage(git_config_set_usage);
if (git_config(show_all_config) < 0 && file && errno)
if (git_config(show_all_config, NULL) < 0 &&
file && errno)
die("unable to read config file %s: %s", file,
strerror(errno));
return 0;

View File

@@ -10,26 +10,54 @@
#include "builtin.h"
static const char diff_files_usage[] =
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|--no-index] [<common diff options>] [<path>...]"
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_files(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
int nongit;
int result;
unsigned options = 0;
prefix = setup_git_directory_gently(&nongit);
init_revisions(&rev, prefix);
git_config(git_diff_basic_config); /* no "diff" UI options */
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
rev.abbrev = 0;
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
argc = 0;
else
argc = setup_revisions(argc, argv, &rev, NULL);
argc = setup_revisions(argc, argv, &rev, NULL);
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "--base"))
rev.max_count = 1;
else if (!strcmp(argv[1], "--ours"))
rev.max_count = 2;
else if (!strcmp(argv[1], "--theirs"))
rev.max_count = 3;
else if (!strcmp(argv[1], "-q"))
options |= DIFF_SILENT_ON_REMOVED;
else
usage(diff_files_usage);
argv++; argc--;
}
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
result = run_diff_files_cmd(&rev, argc, argv);
/*
* Make sure there are NO revision (i.e. pending object) parameter,
* rev.max_count is reasonable (0 <= n <= 3), and
* there is no other revision filtering parameters.
*/
if (rev.pending.nr ||
rev.min_age != -1 || rev.max_age != -1 ||
3 < rev.max_count)
usage(diff_files_usage);
if (rev.max_count == -1 &&
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
rev.combine_merges = rev.dense_combined_merges = 1;
if (read_cache() < 0) {
perror("read_cache");
return -1;
}
result = run_diff_files(&rev, options);
return diff_result_code(&rev.diffopt, result);
}

View File

@@ -17,7 +17,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
int result;
init_revisions(&rev, prefix);
git_config(git_diff_basic_config); /* no "diff" UI options */
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
rev.abbrev = 0;
argc = setup_revisions(argc, argv, &rev, NULL);

View File

@@ -68,7 +68,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int read_stdin = 0;
init_revisions(opt, prefix);
git_config(git_diff_basic_config); /* no "diff" UI options */
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
nr_sha1 = 0;
opt->abbrev = 0;
opt->diff = 1;

View File

@@ -202,6 +202,37 @@ static void refresh_index_quietly(void)
rollback_lock_file(lock_file);
}
static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
{
int result;
unsigned int options = 0;
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "--base"))
revs->max_count = 1;
else if (!strcmp(argv[1], "--ours"))
revs->max_count = 2;
else if (!strcmp(argv[1], "--theirs"))
revs->max_count = 3;
else if (!strcmp(argv[1], "-q"))
options |= DIFF_SILENT_ON_REMOVED;
else
return error("invalid option: %s", argv[1]);
argv++; argc--;
}
if (revs->max_count == -1 &&
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
revs->combine_merges = revs->dense_combined_merges = 1;
if (read_cache() < 0) {
perror("read_cache");
return -1;
}
result = run_diff_files(revs, options);
return diff_result_code(&revs->diffopt, result);
}
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
@@ -230,31 +261,34 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
* N=2, M=0:
* tree vs tree (diff-tree)
*
* N=0, M=0, P=2:
* compare two filesystem entities (aka --no-index).
*
* Other cases are errors.
*/
prefix = setup_git_directory_gently(&nongit);
git_config(git_diff_ui_config);
git_config(git_diff_ui_config, NULL);
if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default;
init_revisions(&rev, prefix);
/* If this is a no-index diff, just run it and exit there. */
diff_no_index(&rev, argc, argv, nongit, prefix);
/* Otherwise, we are doing the usual "git" diff */
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
argc = 0;
else
argc = setup_revisions(argc, argv, &rev, NULL);
if (nongit)
die("Not a git repository");
argc = setup_revisions(argc, argv, &rev, NULL);
if (!rev.diffopt.output_format) {
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
if (diff_setup_done(&rev.diffopt) < 0)
die("diff_setup_done failed");
}
if (rev.diffopt.prefix && nongit) {
rev.diffopt.prefix = NULL;
rev.diffopt.prefix_length = 0;
}
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
@@ -265,7 +299,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
setup_pager();
/* Do we have --cached and not have a pending object, then
/*
* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
*/
if (!rev.pending.nr) {
@@ -333,7 +368,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!ents) {
switch (blobs) {
case 0:
result = run_diff_files_cmd(&rev, argc, argv);
result = builtin_diff_files(&rev, argc, argv);
break;
case 1:
if (paths != 1)

View File

@@ -204,14 +204,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
continue;
if (i == 0)
printf("from :%d\n", mark);
else if (i == 1)
printf("merge :%d", mark);
else
printf(" :%d", mark);
printf("merge :%d\n", mark);
i++;
}
if (i > 1)
printf("\n");
log_tree_diff_flush(rev);
rev->diffopt.output_format = saved_output_format;
@@ -372,7 +368,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
};
/* we handle encodings */
git_config(git_default_config);
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
argc = setup_revisions(argc, argv, &revs, NULL);

View File

@@ -636,7 +636,7 @@ static int remove_duplicates(int nr_heads, char **heads)
return dst;
}
static int fetch_pack_config(const char *var, const char *value)
static int fetch_pack_config(const char *var, const char *value, void *cb)
{
if (strcmp(var, "fetch.unpacklimit") == 0) {
fetch_unpack_limit = git_config_int(var, value);
@@ -648,7 +648,7 @@ static int fetch_pack_config(const char *var, const char *value)
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static struct lock_file lock;
@@ -658,7 +658,7 @@ static void fetch_pack_setup(void)
static int did_setup;
if (did_setup)
return;
git_config(fetch_pack_config);
git_config(fetch_pack_config, NULL);
if (0 <= transfer_unpack_limit)
unpack_limit = transfer_unpack_limit;
else if (0 <= fetch_unpack_limit)

View File

@@ -127,14 +127,8 @@ static struct ref *get_ref_map(struct transport *transport,
/* Merge everything on the command line, but not --tags */
for (rm = ref_map; rm; rm = rm->next)
rm->merge = 1;
if (tags == TAGS_SET) {
struct refspec refspec;
refspec.src = "refs/tags/";
refspec.dst = "refs/tags/";
refspec.pattern = 1;
refspec.force = 0;
get_fetch_map(remote_refs, &refspec, &tail, 0);
}
if (tags == TAGS_SET)
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
} else {
/* Use the defaults */
struct remote *remote = transport->remote;
@@ -292,7 +286,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
{
FILE *fp;
struct commit *commit;
int url_len, i, note_len, shown_url = 0;
int url_len, i, note_len, shown_url = 0, rc = 0;
char note[1024];
const char *what, *kind;
struct ref *rm;
@@ -359,7 +353,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
note);
if (ref)
update_local_ref(ref, what, verbose, note);
rc |= update_local_ref(ref, what, verbose, note);
else
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
SUMMARY_WIDTH, *kind ? kind : "branch",
@@ -374,7 +368,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
}
}
fclose(fp);
return 0;
return rc;
}
/*

View File

@@ -10,7 +10,7 @@ static const char *fmt_merge_msg_usage =
static int merge_summary;
static int fmt_merge_msg_config(const char *key, const char *value)
static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
{
static int found_merge_log = 0;
if (!strcmp("merge.log", key)) {
@@ -260,7 +260,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
unsigned char head_sha1[20];
const char *current_branch;
git_config(fmt_merge_msg_config);
git_config(fmt_merge_msg_config, NULL);
while (argc > 1) {
if (!strcmp(argv[1], "--log") || !strcmp(argv[1], "--summary"))

View File

@@ -35,7 +35,7 @@ static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
static const char *argv_prune[] = {"prune", "--expire", NULL, NULL};
static const char *argv_rerere[] = {"rerere", "gc", NULL};
static int gc_config(const char *var, const char *value)
static int gc_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "gc.packrefs")) {
if (value && !strcmp(value, "notbare"))
@@ -67,7 +67,7 @@ static int gc_config(const char *var, const char *value)
prune_expire = xstrdup(value);
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static void append_option(const char **cmd, const char *opt, int max_length)
@@ -219,14 +219,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
char buf[80];
struct option builtin_gc_options[] = {
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects"),
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects (deprecated)"),
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()
};
git_config(gc_config);
git_config(gc_config, NULL);
if (pack_refs < 0)
pack_refs = !is_bare_repository();
@@ -249,24 +249,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
/*
* Auto-gc should be least intrusive as possible.
*/
prune = 0;
if (!need_to_gc())
return 0;
fprintf(stderr, "Auto packing your repository for optimum "
"performance. You may also\n"
"run \"git gc\" manually. See "
"\"git help gc\" for more information.\n");
} else {
/*
* Use safer (for shared repos) "-A" option to
* repack when not pruning. Auto-gc makes its
* own decision.
*/
if (prune)
append_option(argv_repack, "-a", MAX_ADD);
else
append_option(argv_repack, "-A", MAX_ADD);
}
} else
append_option(argv_repack, "-A", MAX_ADD);
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
return error(FAILED_RUN, argv_pack_refs[0]);

View File

@@ -18,7 +18,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
int get_verbosely = 0;
int get_recover = 0;
git_config(git_default_config);
git_config(git_default_config, NULL);
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 't') {

View File

@@ -104,12 +104,14 @@ static void copy_templates_1(char *path, int baselen,
}
}
static void copy_templates(const char *git_dir, int len, const char *template_dir)
static void copy_templates(const char *template_dir)
{
char path[PATH_MAX];
char template_path[PATH_MAX];
int template_len;
DIR *dir;
const char *git_dir = get_git_dir();
int len = strlen(git_dir);
if (!template_dir)
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
@@ -142,7 +144,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
strcpy(template_path + template_len, "config");
repository_format_version = 0;
git_config_from_file(check_repository_format_version,
template_path);
template_path, NULL);
template_path[template_len] = 0;
if (repository_format_version &&
@@ -156,6 +158,8 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
}
memcpy(path, git_dir, len);
if (len && path[len - 1] != '/')
path[len++] = '/';
path[len] = 0;
copy_templates_1(path, len,
template_path, template_len,
@@ -163,8 +167,9 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
closedir(dir);
}
static int create_default_files(const char *git_dir, const char *template_path)
static int create_default_files(const char *template_path)
{
const char *git_dir = get_git_dir();
unsigned len = strlen(git_dir);
static char path[PATH_MAX];
struct stat st1;
@@ -183,35 +188,27 @@ static int create_default_files(const char *git_dir, const char *template_path)
/*
* Create .git/refs/{heads,tags}
*/
strcpy(path + len, "refs");
safe_create_dir(path, 1);
strcpy(path + len, "refs/heads");
safe_create_dir(path, 1);
strcpy(path + len, "refs/tags");
safe_create_dir(path, 1);
safe_create_dir(git_path("refs"), 1);
safe_create_dir(git_path("refs/heads"), 1);
safe_create_dir(git_path("refs/tags"), 1);
/* First copy the templates -- we might have the default
* config file there, in which case we would want to read
* from it after installing.
*/
path[len] = 0;
copy_templates(path, len, template_path);
copy_templates(template_path);
git_config(git_default_config);
git_config(git_default_config, NULL);
/*
* We would have created the above under user's umask -- under
* shared-repository settings, we would need to fix them up.
*/
if (shared_repository) {
path[len] = 0;
adjust_shared_perm(path);
strcpy(path + len, "refs");
adjust_shared_perm(path);
strcpy(path + len, "refs/heads");
adjust_shared_perm(path);
strcpy(path + len, "refs/tags");
adjust_shared_perm(path);
adjust_shared_perm(get_git_dir());
adjust_shared_perm(git_path("refs"));
adjust_shared_perm(git_path("refs/heads"));
adjust_shared_perm(git_path("refs/tags"));
}
/*
@@ -251,12 +248,14 @@ static int create_default_files(const char *git_dir, const char *template_path)
/* allow template config file to override the default */
if (log_all_ref_updates == -1)
git_config_set("core.logallrefupdates", "true");
if (work_tree != git_work_tree_cfg)
if (prefixcmp(git_dir, work_tree) ||
strcmp(git_dir + strlen(work_tree), "/.git")) {
git_config_set("core.worktree", work_tree);
}
}
/* Check if symlink is supported in the work tree */
if (!reinit) {
/* Check if symlink is supported in the work tree */
path[len] = 0;
strcpy(path + len, "tXXXXXX");
if (!close(xmkstemp(path)) &&
@@ -267,111 +266,24 @@ static int create_default_files(const char *git_dir, const char *template_path)
unlink(path); /* good */
else
git_config_set("core.symlinks", "false");
/* Check if the filesystem is case-insensitive */
path[len] = 0;
strcpy(path + len, "CoNfIg");
if (!access(path, F_OK))
git_config_set("core.ignorecase", "true");
}
return reinit;
}
static void guess_repository_type(const char *git_dir)
int init_db(const char *template_dir, unsigned int flags)
{
char cwd[PATH_MAX];
const char *slash;
if (0 <= is_bare_repository_cfg)
return;
if (!git_dir)
return;
/*
* "GIT_DIR=. git init" is always bare.
* "GIT_DIR=`pwd` git init" too.
*/
if (!strcmp(".", git_dir))
goto force_bare;
if (!getcwd(cwd, sizeof(cwd)))
die("cannot tell cwd");
if (!strcmp(git_dir, cwd))
goto force_bare;
/*
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
*/
if (!strcmp(git_dir, ".git"))
return;
slash = strrchr(git_dir, '/');
if (slash && !strcmp(slash, "/.git"))
return;
/*
* Otherwise it is often bare. At this point
* we are just guessing.
*/
force_bare:
is_bare_repository_cfg = 1;
return;
}
static const char init_db_usage[] =
"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
/*
* If you want to, you can share the DB area with any number of branches.
* That has advantages: you can save space by sharing all the SHA1 objects.
* On the other hand, it might just make lookup slower and messier. You
* be the judge. The default case is to have one DB per managed directory.
*/
int cmd_init_db(int argc, const char **argv, const char *prefix)
{
const char *git_dir;
const char *sha1_dir;
const char *template_dir = NULL;
char *path;
int len, i, reinit;
int quiet = 0;
int len, reinit;
for (i = 1; i < argc; i++, argv++) {
const char *arg = argv[1];
if (!prefixcmp(arg, "--template="))
template_dir = arg+11;
else if (!strcmp(arg, "--shared"))
shared_repository = PERM_GROUP;
else if (!prefixcmp(arg, "--shared="))
shared_repository = git_config_perm("arg", arg+9);
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
quiet = 1;
else
usage(init_db_usage);
}
/*
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
* without --bare. Catch the error early.
*/
git_dir = getenv(GIT_DIR_ENVIRONMENT);
if ((!git_dir || is_bare_repository_cfg == 1)
&& getenv(GIT_WORK_TREE_ENVIRONMENT))
die("%s (or --work-tree=<directory>) not allowed without "
"specifying %s (or --git-dir=<directory>)",
GIT_WORK_TREE_ENVIRONMENT,
GIT_DIR_ENVIRONMENT);
guess_repository_type(git_dir);
if (is_bare_repository_cfg <= 0) {
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
if (!getcwd(git_work_tree_cfg, PATH_MAX))
die ("Cannot access current working directory.");
if (access(get_git_work_tree(), X_OK))
die ("Cannot access work tree '%s'",
get_git_work_tree());
}
/*
* Set up the default .git directory contents
*/
git_dir = getenv(GIT_DIR_ENVIRONMENT);
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
safe_create_dir(git_dir, 0);
safe_create_dir(get_git_dir(), 0);
/* Check to see if the repository version is right.
* Note that a newly created repository does not have
@@ -380,11 +292,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
*/
check_repository_format();
reinit = create_default_files(git_dir, template_dir);
reinit = create_default_files(template_dir);
/*
* And set up the object store.
*/
sha1_dir = get_object_directory();
len = strlen(sha1_dir);
path = xmalloc(len + 40);
@@ -414,11 +323,122 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
git_config_set("receive.denyNonFastforwards", "true");
}
if (!quiet)
if (!(flags & INIT_DB_QUIET))
printf("%s%s Git repository in %s/\n",
reinit ? "Reinitialized existing" : "Initialized empty",
shared_repository ? " shared" : "",
git_dir);
get_git_dir());
return 0;
}
static int guess_repository_type(const char *git_dir)
{
char cwd[PATH_MAX];
const char *slash;
/*
* "GIT_DIR=. git init" is always bare.
* "GIT_DIR=`pwd` git init" too.
*/
if (!strcmp(".", git_dir))
return 1;
if (!getcwd(cwd, sizeof(cwd)))
die("cannot tell cwd");
if (!strcmp(git_dir, cwd))
return 1;
/*
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
*/
if (!strcmp(git_dir, ".git"))
return 0;
slash = strrchr(git_dir, '/');
if (slash && !strcmp(slash, "/.git"))
return 0;
/*
* Otherwise it is often bare. At this point
* we are just guessing.
*/
return 1;
}
static const char init_db_usage[] =
"git-init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
/*
* If you want to, you can share the DB area with any number of branches.
* That has advantages: you can save space by sharing all the SHA1 objects.
* On the other hand, it might just make lookup slower and messier. You
* be the judge. The default case is to have one DB per managed directory.
*/
int cmd_init_db(int argc, const char **argv, const char *prefix)
{
const char *git_dir;
const char *template_dir = NULL;
unsigned int flags = 0;
int i;
for (i = 1; i < argc; i++, argv++) {
const char *arg = argv[1];
if (!prefixcmp(arg, "--template="))
template_dir = arg+11;
else if (!strcmp(arg, "--bare")) {
static char git_dir[PATH_MAX+1];
is_bare_repository_cfg = 1;
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
sizeof(git_dir)), 0);
} else if (!strcmp(arg, "--shared"))
shared_repository = PERM_GROUP;
else if (!prefixcmp(arg, "--shared="))
shared_repository = git_config_perm("arg", arg+9);
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
flags |= INIT_DB_QUIET;
else
usage(init_db_usage);
}
/*
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
* without --bare. Catch the error early.
*/
git_dir = getenv(GIT_DIR_ENVIRONMENT);
if ((!git_dir || is_bare_repository_cfg == 1)
&& getenv(GIT_WORK_TREE_ENVIRONMENT))
die("%s (or --work-tree=<directory>) not allowed without "
"specifying %s (or --git-dir=<directory>)",
GIT_WORK_TREE_ENVIRONMENT,
GIT_DIR_ENVIRONMENT);
/*
* Set up the default .git directory contents
*/
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
if (is_bare_repository_cfg < 0)
is_bare_repository_cfg = guess_repository_type(git_dir);
if (!is_bare_repository_cfg) {
if (git_dir) {
const char *git_dir_parent = strrchr(git_dir, '/');
if (git_dir_parent) {
char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
git_work_tree_cfg = xstrdup(make_absolute_path(rel));
free(rel);
}
}
if (!git_work_tree_cfg) {
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
if (!getcwd(git_work_tree_cfg, PATH_MAX))
die ("Cannot access current working directory.");
}
if (access(get_git_work_tree(), X_OK))
die ("Cannot access work tree '%s'",
get_git_work_tree());
}
set_git_dir(make_absolute_path(git_dir));
return init_db(template_dir, flags);
}

View File

@@ -18,6 +18,9 @@
#include "run-command.h"
#include "shortlog.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
static int default_show_root = 1;
static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
@@ -61,7 +64,12 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
if (default_date_mode)
rev->date_mode = parse_date_format(default_date_mode);
argc = setup_revisions(argc, argv, rev, "HEAD");
if (rev->diffopt.pickaxe || rev->diffopt.filter)
rev->always_show_header = 0;
if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
@@ -222,7 +230,7 @@ static int cmd_log_walk(struct rev_info *rev)
return 0;
}
static int git_log_config(const char *var, const char *value)
static int git_log_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "format.pretty"))
return git_config_string(&fmt_pretty, var, value);
@@ -232,18 +240,20 @@ static int git_log_config(const char *var, const char *value)
fmt_patch_subject_prefix = xstrdup(value);
return 0;
}
if (!strcmp(var, "log.date"))
return git_config_string(&default_date_mode, var, value);
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
}
return git_diff_ui_config(var, value);
return git_diff_ui_config(var, value, cb);
}
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
git_config(git_log_config);
git_config(git_log_config, NULL);
if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default;
@@ -319,7 +329,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
struct object_array_entry *objects;
int i, count, ret = 0;
git_config(git_log_config);
git_config(git_log_config, NULL);
if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default;
@@ -383,7 +393,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
git_config(git_log_config);
git_config(git_log_config, NULL);
if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default;
@@ -416,7 +426,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
git_config(git_log_config);
git_config(git_log_config, NULL);
if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default;
@@ -471,7 +481,7 @@ static void add_header(const char *value)
extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
}
static int git_format_config(const char *var, const char *value)
static int git_format_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "format.headers")) {
if (!value)
@@ -504,7 +514,7 @@ static int git_format_config(const char *var, const char *value)
return 0;
}
return git_log_config(var, value);
return git_log_config(var, value, cb);
}
@@ -771,7 +781,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char *add_signoff = NULL;
struct strbuf buf;
git_config(git_format_config);
git_config(git_format_config, NULL);
init_revisions(&rev, prefix);
rev.commit_format = CMIT_FMT_EMAIL;
rev.verbose_header = 1;

View File

@@ -437,7 +437,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
memset(&dir, 0, sizeof(dir));
if (prefix)
prefix_offset = strlen(prefix);
git_config(git_default_config);
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

View File

@@ -122,7 +122,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
unsigned char sha1[20];
struct tree *tree;
git_config(git_default_config);
git_config(git_default_config, NULL);
ls_tree_prefix = prefix;
if (prefix && *prefix)
chomp_prefix = strlen(prefix);

View File

@@ -434,6 +434,7 @@ static int read_one_header_line(char *line, int sz, FILE *in)
static int decode_q_segment(char *in, char *ot, unsigned otsize, char *ep, int rfc2047)
{
char *otbegin = ot;
char *otend = ot + otsize;
int c;
while ((c = *in++) != 0 && (in <= ep)) {
@@ -453,13 +454,14 @@ static int decode_q_segment(char *in, char *ot, unsigned otsize, char *ep, int r
*ot++ = c;
}
*ot = 0;
return 0;
return (ot - otbegin);
}
static int decode_b_segment(char *in, char *ot, unsigned otsize, char *ep)
{
/* Decode in..ep, possibly in-place to ot */
int c, pos = 0, acc = 0;
char *otbegin = ot;
char *otend = ot + otsize;
while ((c = *in++) != 0 && (in <= ep)) {
@@ -505,7 +507,7 @@ static int decode_b_segment(char *in, char *ot, unsigned otsize, char *ep)
}
}
*ot = 0;
return 0;
return (ot - otbegin);
}
/*
@@ -623,25 +625,24 @@ static void decode_header(char *it, unsigned itsize)
convert_to_utf8(it, itsize, "");
}
static void decode_transfer_encoding(char *line, unsigned linesize)
static int decode_transfer_encoding(char *line, unsigned linesize, int inputlen)
{
char *ep;
switch (transfer_encoding) {
case TE_QP:
ep = line + strlen(line);
decode_q_segment(line, line, linesize, ep, 0);
break;
ep = line + inputlen;
return decode_q_segment(line, line, linesize, ep, 0);
case TE_BASE64:
ep = line + strlen(line);
decode_b_segment(line, line, linesize, ep);
break;
ep = line + inputlen;
return decode_b_segment(line, line, linesize, ep);
case TE_DONTCARE:
break;
default:
return inputlen;
}
}
static int handle_filter(char *line, unsigned linesize);
static int handle_filter(char *line, unsigned linesize, int linelen);
static int find_boundary(void)
{
@@ -669,7 +670,7 @@ again:
"can't recover\n");
exit(1);
}
handle_filter(newline, sizeof(newline));
handle_filter(newline, sizeof(newline), strlen(newline));
/* skip to the next boundary */
if (!find_boundary())
@@ -759,14 +760,14 @@ static int handle_commit_msg(char *line, unsigned linesize)
return 0;
}
static int handle_patch(char *line)
static int handle_patch(char *line, int len)
{
fputs(line, patchfile);
fwrite(line, 1, len, patchfile);
patch_lines++;
return 0;
}
static int handle_filter(char *line, unsigned linesize)
static int handle_filter(char *line, unsigned linesize, int linelen)
{
static int filter = 0;
@@ -779,7 +780,7 @@ static int handle_filter(char *line, unsigned linesize)
break;
filter++;
case 1:
if (!handle_patch(line))
if (!handle_patch(line, linelen))
break;
filter++;
default:
@@ -794,6 +795,7 @@ static void handle_body(void)
int rc = 0;
static char newline[2000];
static char *np = newline;
int len = strlen(line);
/* Skip up to the first boundary */
if (content_top->boundary) {
@@ -805,16 +807,19 @@ static void handle_body(void)
/* process any boundary lines */
if (content_top->boundary && is_multipart_boundary(line)) {
/* flush any leftover */
if ((transfer_encoding == TE_BASE64) &&
(np != newline)) {
handle_filter(newline, sizeof(newline));
}
if (np != newline)
handle_filter(newline, sizeof(newline),
np - newline);
if (!handle_boundary())
return;
}
/* Unwrap transfer encoding */
decode_transfer_encoding(line, sizeof(line));
len = decode_transfer_encoding(line, sizeof(line), len);
if (len < 0) {
error("Malformed input line");
return;
}
switch (transfer_encoding) {
case TE_BASE64:
@@ -824,39 +829,40 @@ static void handle_body(void)
/* binary data most likely doesn't have newlines */
if (message_type != TYPE_TEXT) {
rc = handle_filter(line, sizeof(newline));
rc = handle_filter(line, sizeof(line), len);
break;
}
/* this is a decoded line that may contain
/*
* This is a decoded line that may contain
* multiple new lines. Pass only one chunk
* at a time to handle_filter()
*/
do {
while (*op != '\n' && *op != 0)
while (op < line + len && *op != '\n')
*np++ = *op++;
*np = *op;
if (*np != 0) {
/* should be sitting on a new line */
*(++np) = 0;
op++;
rc = handle_filter(newline, sizeof(newline));
rc = handle_filter(newline, sizeof(newline), np - newline);
np = newline;
}
} while (*op != 0);
/* the partial chunk is saved in newline and
* will be appended by the next iteration of fgets
} while (op < line + len);
/*
* The partial chunk is saved in newline and will be
* appended by the next iteration of read_line_with_nul().
*/
break;
}
default:
rc = handle_filter(line, sizeof(newline));
rc = handle_filter(line, sizeof(line), len);
}
if (rc)
/* nothing left to filter */
break;
} while (fgets(line, sizeof(line), fin));
} while ((len = read_line_with_nul(line, sizeof(line), fin)));
return;
}
@@ -962,7 +968,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
/* NEEDSWORK: might want to do the optional .git/ directory
* discovery
*/
git_config(git_default_config);
git_config(git_default_config, NULL);
def_charset = (git_commit_encoding ? git_commit_encoding : "utf-8");
metainfo_charset = def_charset;

View File

@@ -45,6 +45,24 @@ static int is_from_line(const char *line, int len)
/* Could be as small as 64, enough to hold a Unix "From " line. */
static char buf[4096];
/* We cannot use fgets() because our lines can contain NULs */
int read_line_with_nul(char *buf, int size, FILE *in)
{
int len = 0, c;
for (;;) {
c = getc(in);
if (c == EOF)
break;
buf[len++] = c;
if (c == '\n' || len + 1 >= size)
break;
}
buf[len] = '\0';
return len;
}
/* Called with the first line (potentially partial)
* already in buf[] -- normally that should begin with
* the Unix "From " line. Write it into the specified
@@ -70,19 +88,19 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
* "From " and having something that looks like a date format.
*/
for (;;) {
int is_partial = (buf[len-1] != '\n');
int is_partial = len && buf[len-1] != '\n';
if (fputs(buf, output) == EOF)
if (fwrite(buf, 1, len, output) != len)
die("cannot write output");
if (fgets(buf, sizeof(buf), mbox) == NULL) {
len = read_line_with_nul(buf, sizeof(buf), mbox);
if (len == 0) {
if (feof(mbox)) {
status = 1;
break;
}
die("cannot read mbox");
}
len = strlen(buf);
if (!is_partial && !is_bare && is_from_line(buf, len))
break; /* done with one message */
}

View File

@@ -28,7 +28,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
unsigned char rev1key[20], rev2key[20];
int show_all = 0;
git_config(git_default_config);
git_config(git_default_config, NULL);
while (1 < argc && argv[1][0] == '-') {
const char *arg = argv[1];

View File

@@ -1340,7 +1340,7 @@ static struct commit *get_ref(const char *ref)
return (struct commit *)object;
}
static int merge_config(const char *var, const char *value)
static int merge_config(const char *var, const char *value, void *cb)
{
if (!strcasecmp(var, "merge.verbosity")) {
verbosity = git_config_int(var, value);
@@ -1354,7 +1354,7 @@ static int merge_config(const char *var, const char *value)
merge_rename_limit = git_config_int(var, value);
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
@@ -1375,7 +1375,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
subtree_merge = 1;
}
git_config(merge_config);
git_config(merge_config, NULL);
if (getenv("GIT_MERGE_VERBOSITY"))
verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);

View File

@@ -81,7 +81,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct path_list deleted = {NULL, 0, 0, 0};
struct path_list changed = {NULL, 0, 0, 0};
git_config(git_default_config);
git_config(git_default_config, NULL);
newfd = hold_locked_index(&lock_file, 1);
if (read_cache() < 0)
@@ -256,7 +256,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
for (i = 0; i < added.nr; i++) {
const char *path = added.items[i].path;
add_file_to_cache(path, verbose);
if (add_file_to_cache(path, verbose ? ADD_CACHE_VERBOSE : 0))
die("updating index entries failed");
}
for (i = 0; i < deleted.nr; i++)

View File

@@ -195,7 +195,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
OPT_END(),
};
git_config(git_default_config);
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, opts, name_rev_usage, 0);
if (!!all + !!transform_stdin + !!argc > 1) {
error("Specify either a list, or --all, not both!");

View File

@@ -28,7 +28,8 @@ git-pack-objects [{ -q | --progress | --all-progress }] \n\
[--window=N] [--window-memory=N] [--depth=N] \n\
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
[--stdout | base-name] [--include-tag] [--keep-unreachable] \n\
[--stdout | base-name] [--include-tag] \n\
[--keep-unreachable | --unpack-unreachable] \n\
[<ref-list | <object-list]";
struct object_entry {
@@ -43,6 +44,7 @@ struct object_entry {
*/
void *delta_data; /* cached delta (uncompressed) */
unsigned long delta_size; /* delta data size (uncompressed) */
unsigned long z_delta_size; /* delta data size (compressed) */
unsigned int hash; /* name hint hash */
enum object_type type;
enum object_type in_pack_type; /* could be delta */
@@ -65,7 +67,8 @@ static struct pack_idx_entry **written_list;
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
static int non_empty;
static int no_reuse_delta, no_reuse_object, keep_unreachable, include_tag;
static int reuse_delta = 1, reuse_object = 1;
static int keep_unreachable, unpack_unreachable, include_tag;
static int local;
static int incremental;
static int allow_ofs_delta;
@@ -102,24 +105,53 @@ static uint32_t written, written_delta;
static uint32_t reused, reused_delta;
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
static void *get_delta(struct object_entry *entry)
{
unsigned long othersize, delta_size;
unsigned long size, base_size, delta_size;
void *buf, *base_buf, *delta_buf;
enum object_type type;
void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
void *delta_buf;
if (!otherbuf)
buf = read_sha1_file(entry->idx.sha1, &type, &size);
if (!buf)
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size);
if (!base_buf)
die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
delta_buf = diff_delta(otherbuf, othersize,
delta_buf = diff_delta(base_buf, base_size,
buf, size, &delta_size, 0);
if (!delta_buf || delta_size != entry->delta_size)
if (!delta_buf || delta_size != entry->delta_size)
die("delta size changed");
free(buf);
free(otherbuf);
free(buf);
free(base_buf);
return delta_buf;
}
static unsigned long do_compress(void **pptr, unsigned long size)
{
z_stream stream;
void *in, *out;
unsigned long maxsize;
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, pack_compression_level);
maxsize = deflateBound(&stream, size);
in = *pptr;
out = xmalloc(maxsize);
*pptr = out;
stream.next_in = in;
stream.avail_in = size;
stream.next_out = out;
stream.avail_out = maxsize;
while (deflate(&stream, Z_FINISH) == Z_OK)
; /* nothing */
deflateEnd(&stream);
free(in);
return stream.total_out;
}
/*
* The per-object header is a pretty dense thing, which is
* - first byte: low four bits are "size", then three bits of "type",
@@ -222,42 +254,42 @@ static unsigned long write_object(struct sha1file *f,
struct object_entry *entry,
off_t write_offset)
{
unsigned long size;
enum object_type type;
unsigned long size, limit, datalen;
void *buf;
unsigned char header[10];
unsigned char dheader[10];
unsigned char header[10], dheader[10];
unsigned hdrlen;
off_t datalen;
enum object_type obj_type;
int to_reuse = 0;
/* write limit if limited packsize and not first object */
unsigned long limit = pack_size_limit && nr_written ?
pack_size_limit - write_offset : 0;
/* no if no delta */
int usable_delta = !entry->delta ? 0 :
/* yes if unlimited packfile */
!pack_size_limit ? 1 :
/* no if base written to previous pack */
entry->delta->idx.offset == (off_t)-1 ? 0 :
/* otherwise double-check written to this
* pack, like we do below
*/
entry->delta->idx.offset ? 1 : 0;
enum object_type type;
int usable_delta, to_reuse;
if (!pack_to_stdout)
crc32_begin(f);
obj_type = entry->type;
if (no_reuse_object)
type = entry->type;
/* write limit if limited packsize and not first object */
limit = pack_size_limit && nr_written ?
pack_size_limit - write_offset : 0;
if (!entry->delta)
usable_delta = 0; /* no delta */
else if (!pack_size_limit)
usable_delta = 1; /* unlimited packfile */
else if (entry->delta->idx.offset == (off_t)-1)
usable_delta = 0; /* base was written to another pack */
else if (entry->delta->idx.offset)
usable_delta = 1; /* base already exists in this pack */
else
usable_delta = 0; /* base could end up in another pack */
if (!reuse_object)
to_reuse = 0; /* explicit */
else if (!entry->in_pack)
to_reuse = 0; /* can't reuse what we don't have */
else if (obj_type == OBJ_REF_DELTA || obj_type == OBJ_OFS_DELTA)
else if (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA)
/* check_object() decided it for us ... */
to_reuse = usable_delta;
/* ... but pack split may override that */
else if (obj_type != entry->in_pack_type)
else if (type != entry->in_pack_type)
to_reuse = 0; /* pack has delta which is unusable */
else if (entry->delta)
to_reuse = 0; /* we want to pack afresh */
@@ -267,50 +299,42 @@ static unsigned long write_object(struct sha1file *f,
*/
if (!to_reuse) {
z_stream stream;
unsigned long maxsize;
void *out;
if (!usable_delta) {
buf = read_sha1_file(entry->idx.sha1, &obj_type, &size);
buf = read_sha1_file(entry->idx.sha1, &type, &size);
if (!buf)
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
/*
* make sure no cached delta data remains from a
* previous attempt before a pack split occured.
*/
free(entry->delta_data);
entry->delta_data = NULL;
entry->z_delta_size = 0;
} else if (entry->delta_data) {
size = entry->delta_size;
buf = entry->delta_data;
entry->delta_data = NULL;
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
} else {
buf = read_sha1_file(entry->idx.sha1, &type, &size);
if (!buf)
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
buf = delta_against(buf, size, entry);
buf = get_delta(entry);
size = entry->delta_size;
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
}
/* compress the data to store and put compressed length in datalen */
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, pack_compression_level);
maxsize = deflateBound(&stream, size);
out = xmalloc(maxsize);
/* Compress it */
stream.next_in = buf;
stream.avail_in = size;
stream.next_out = out;
stream.avail_out = maxsize;
while (deflate(&stream, Z_FINISH) == Z_OK)
/* nothing */;
deflateEnd(&stream);
datalen = stream.total_out;
if (entry->z_delta_size)
datalen = entry->z_delta_size;
else
datalen = do_compress(&buf, size);
/*
* The object header is a byte of 'type' followed by zero or
* more bytes of length.
*/
hdrlen = encode_header(obj_type, size, header);
hdrlen = encode_header(type, size, header);
if (obj_type == OBJ_OFS_DELTA) {
if (type == OBJ_OFS_DELTA) {
/*
* Deltas with relative base contain an additional
* encoding of the relative offset for the delta
@@ -322,20 +346,18 @@ static unsigned long write_object(struct sha1file *f,
while (ofs >>= 7)
dheader[--pos] = 128 | (--ofs & 127);
if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
free(out);
free(buf);
return 0;
}
sha1write(f, header, hdrlen);
sha1write(f, dheader + pos, sizeof(dheader) - pos);
hdrlen += sizeof(dheader) - pos;
} else if (obj_type == OBJ_REF_DELTA) {
} else if (type == OBJ_REF_DELTA) {
/*
* Deltas with a base reference contain
* an additional 20 bytes for the base sha1.
*/
if (limit && hdrlen + 20 + datalen + 20 >= limit) {
free(out);
free(buf);
return 0;
}
@@ -344,14 +366,12 @@ static unsigned long write_object(struct sha1file *f,
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit) {
free(out);
free(buf);
return 0;
}
sha1write(f, header, hdrlen);
}
sha1write(f, out, datalen);
free(out);
sha1write(f, buf, datalen);
free(buf);
}
else {
@@ -361,11 +381,11 @@ static unsigned long write_object(struct sha1file *f,
off_t offset;
if (entry->delta) {
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
reused_delta++;
}
hdrlen = encode_header(obj_type, entry->size, header);
hdrlen = encode_header(type, entry->size, header);
offset = entry->in_pack_offset;
revidx = find_pack_revindex(p, offset);
datalen = revidx[1].offset - offset;
@@ -374,7 +394,7 @@ static unsigned long write_object(struct sha1file *f,
die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
offset += entry->in_pack_header_size;
datalen -= entry->in_pack_header_size;
if (obj_type == OBJ_OFS_DELTA) {
if (type == OBJ_OFS_DELTA) {
off_t ofs = entry->idx.offset - entry->delta->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
@@ -385,7 +405,7 @@ static unsigned long write_object(struct sha1file *f,
sha1write(f, header, hdrlen);
sha1write(f, dheader + pos, sizeof(dheader) - pos);
hdrlen += sizeof(dheader) - pos;
} else if (obj_type == OBJ_REF_DELTA) {
} else if (type == OBJ_REF_DELTA) {
if (limit && hdrlen + 20 + datalen + 20 >= limit)
return 0;
sha1write(f, header, hdrlen);
@@ -452,11 +472,10 @@ static void write_pack_file(void)
struct sha1file *f;
off_t offset, offset_one, last_obj_offset = 0;
struct pack_header hdr;
int do_progress = progress >> pack_to_stdout;
uint32_t nr_remaining = nr_result;
time_t last_mtime = 0;
if (do_progress)
if (progress > pack_to_stdout)
progress_state = start_progress("Writing objects", nr_result);
written_list = xmalloc(nr_objects * sizeof(*written_list));
@@ -495,11 +514,14 @@ static void write_pack_file(void)
* Did we write the wrong # entries in the header?
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout || nr_written == nr_remaining) {
sha1close(f, sha1, 1);
if (pack_to_stdout) {
sha1close(f, sha1, CSUM_CLOSE);
} else if (nr_written == nr_remaining) {
sha1close(f, sha1, CSUM_FSYNC);
} else {
int fd = sha1close(f, NULL, 0);
fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
fsync_or_die(fd, pack_tmp_name);
close(fd);
}
@@ -1022,7 +1044,7 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
return;
case OBJ_REF_DELTA:
if (!no_reuse_delta && !entry->preferred_base)
if (reuse_delta && !entry->preferred_base)
base_ref = use_pack(p, &w_curs,
entry->in_pack_offset + used, NULL);
entry->in_pack_header_size = used + 20;
@@ -1045,7 +1067,7 @@ static void check_object(struct object_entry *entry)
die("delta base offset out of bound for %s",
sha1_to_hex(entry->idx.sha1));
ofs = entry->in_pack_offset - ofs;
if (!no_reuse_delta && !entry->preferred_base) {
if (reuse_delta && !entry->preferred_base) {
struct revindex_entry *revidx;
revidx = find_pack_revindex(p, ofs);
base_ref = nth_packed_object_sha1(p, revidx->nr);
@@ -1233,7 +1255,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
* We do not bother to try a delta that we discarded
* on an earlier try, but only when reusing delta data.
*/
if (!no_reuse_delta && trg_entry->in_pack &&
if (reuse_delta && trg_entry->in_pack &&
trg_entry->in_pack == src_entry->in_pack &&
trg_entry->in_pack_type != OBJ_REF_DELTA &&
trg_entry->in_pack_type != OBJ_OFS_DELTA)
@@ -1441,11 +1463,34 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
best_base = other_idx;
}
/*
* If we decided to cache the delta data, then it is best
* to compress it right away. First because we have to do
* it anyway, and doing it here while we're threaded will
* save a lot of time in the non threaded write phase,
* as well as allow for caching more deltas within
* the same cache size limit.
* ...
* But only if not writing to stdout, since in that case
* the network is most likely throttling writes anyway,
* and therefore it is best to go to the write phase ASAP
* instead, as we can afford spending more time compressing
* between writes at that moment.
*/
if (entry->delta_data && !pack_to_stdout) {
entry->z_delta_size = do_compress(&entry->delta_data,
entry->delta_size);
cache_lock();
delta_cache_size -= entry->delta_size;
delta_cache_size += entry->z_delta_size;
cache_unlock();
}
/* if we made n a delta, and if n is already at max
* depth, leaving it in the window is pointless. we
* should evict it first.
*/
if (entry->delta && depth <= n->depth)
if (entry->delta && max_depth <= n->depth)
continue;
/*
@@ -1688,7 +1733,7 @@ static void prepare_pack(int window, int depth)
if (entry->delta)
/* This happens if we decided to reuse existing
* delta from a pack. "!no_reuse_delta &&" is implied.
* delta from a pack. "reuse_delta &&" is implied.
*/
continue;
@@ -1718,7 +1763,7 @@ static void prepare_pack(int window, int depth)
free(delta_list);
}
static int git_pack_config(const char *k, const char *v)
static int git_pack_config(const char *k, const char *v, void *cb)
{
if(!strcmp(k, "pack.window")) {
window = git_config_int(k, v);
@@ -1771,7 +1816,7 @@ static int git_pack_config(const char *k, const char *v)
pack_size_limit_cfg = git_config_ulong(k, v);
return 0;
}
return git_default_config(k, v);
return git_default_config(k, v, cb);
}
static void read_object_list_from_stdin(void)
@@ -1905,6 +1950,32 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
free(in_pack.array);
}
static void loosen_unused_packed_objects(struct rev_info *revs)
{
struct packed_git *p;
uint32_t i;
const unsigned char *sha1;
for (p = packed_git; p; p = p->next) {
for (i = 0; i < revs->num_ignore_packed; i++) {
if (matches_pack_name(p, revs->ignore_packed[i]))
break;
}
if (revs->num_ignore_packed <= i)
continue;
if (open_pack_index(p))
die("cannot open pack index");
for (i = 0; i < p->num_objects; i++) {
sha1 = nth_packed_object_sha1(p, i);
if (!locate_object_entry(sha1))
if (force_object_loose(sha1, p->mtime))
die("unable to force loose object");
}
}
}
static void get_object_list(int ac, const char **av)
{
struct rev_info revs;
@@ -1939,6 +2010,8 @@ static void get_object_list(int ac, const char **av)
if (keep_unreachable)
add_objects_in_unpacked_packs(&revs);
if (unpack_unreachable)
loosen_unused_packed_objects(&revs);
}
static int adjust_perm(const char *path, mode_t mode)
@@ -1963,7 +2036,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
rp_ac = 2;
git_config(git_pack_config);
git_config(git_pack_config, NULL);
if (!pack_compression_seen && core_compression_seen)
pack_compression_level = core_compression_level;
@@ -2050,11 +2123,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp("--no-reuse-delta", arg)) {
no_reuse_delta = 1;
reuse_delta = 0;
continue;
}
if (!strcmp("--no-reuse-object", arg)) {
no_reuse_object = no_reuse_delta = 1;
reuse_object = reuse_delta = 0;
continue;
}
if (!strcmp("--delta-base-offset", arg)) {
@@ -2073,6 +2146,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
keep_unreachable = 1;
continue;
}
if (!strcmp("--unpack-unreachable", arg)) {
unpack_unreachable = 1;
continue;
}
if (!strcmp("--include-tag", arg)) {
include_tag = 1;
continue;
@@ -2138,6 +2215,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!pack_to_stdout && thin)
die("--thin cannot be used to build an indexable pack.");
if (keep_unreachable && unpack_unreachable)
die("--keep-unreachable and --unpack-unreachable are incompatible.");
#ifdef THREADED_DELTA_SEARCH
if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus();

View File

@@ -85,7 +85,6 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix)
/* Handle arguments here .. */
usage(prune_packed_usage);
}
sync();
prune_packed_objects(opts);
return 0;
}

View File

@@ -156,7 +156,6 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
mark_reachable_objects(&revs, 1);
prune_object_dir(get_object_directory());
sync();
prune_packed_objects(show_only);
remove_temporary_files();
return 0;

View File

@@ -104,12 +104,10 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
opts.src_index = &the_index;
opts.dst_index = &the_index;
git_config(git_default_config);
git_config(git_default_config, NULL);
newfd = hold_locked_index(&lock_file, 1);
git_config(git_default_config);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

View File

@@ -329,7 +329,7 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused
return 0;
}
static int reflog_expire_config(const char *var, const char *value)
static int reflog_expire_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "gc.reflogexpire")) {
if (!value)
@@ -343,7 +343,7 @@ static int reflog_expire_config(const char *var, const char *value)
default_reflog_expire_unreachable = approxidate(value);
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
@@ -352,7 +352,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
unsigned long now = time(NULL);
int i, status, do_all;
git_config(reflog_expire_config);
git_config(reflog_expire_config, NULL);
save_commit_buffer = 0;
do_all = status = 0;

View File

@@ -153,7 +153,7 @@ struct branch_info {
static struct path_list branch_list;
static int config_read_branches(const char *key, const char *value)
static int config_read_branches(const char *key, const char *value, void *cb)
{
if (!prefixcmp(key, "branch.")) {
char *name;
@@ -200,13 +200,12 @@ static void read_branches(void)
{
if (branch_list.nr)
return;
git_config(config_read_branches);
git_config(config_read_branches, NULL);
sort_path_list(&branch_list);
}
struct ref_states {
struct remote *remote;
struct strbuf remote_prefix;
struct path_list new, stale, tracked;
};
@@ -262,36 +261,72 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)
}
free_refs(fetch_map);
strbuf_addf(&states->remote_prefix,
"refs/remotes/%s/", states->remote->name);
for_each_ref(handle_one_branch, states);
sort_path_list(&states->stale);
return 0;
}
struct known_remote {
struct known_remote *next;
struct remote *remote;
};
struct known_remotes {
struct remote *to_delete;
struct known_remote *list;
};
static int add_known_remote(struct remote *remote, void *cb_data)
{
struct known_remotes *all = cb_data;
struct known_remote *r;
if (!strcmp(all->to_delete->name, remote->name))
return 0;
r = xmalloc(sizeof(*r));
r->remote = remote;
r->next = all->list;
all->list = r;
return 0;
}
struct branches_for_remote {
const char *prefix;
struct remote *remote;
struct path_list *branches;
struct known_remotes *keep;
};
static int add_branch_for_removal(const char *refname,
const unsigned char *sha1, int flags, void *cb_data)
{
struct branches_for_remote *branches = cb_data;
struct refspec refspec;
struct path_list_item *item;
struct known_remote *kr;
if (!prefixcmp(refname, branches->prefix)) {
struct path_list_item *item;
memset(&refspec, 0, sizeof(refspec));
refspec.dst = (char *)refname;
if (remote_find_tracking(branches->remote, &refspec))
return 0;
/* make sure that symrefs are deleted */
if (flags & REF_ISSYMREF)
return unlink(git_path(refname));
item = path_list_append(refname, branches->branches);
item->util = xmalloc(20);
hashcpy(item->util, sha1);
/* don't delete a branch if another remote also uses it */
for (kr = branches->keep->list; kr; kr = kr->next) {
memset(&refspec, 0, sizeof(refspec));
refspec.dst = (char *)refname;
if (!remote_find_tracking(kr->remote, &refspec))
return 0;
}
/* make sure that symrefs are deleted */
if (flags & REF_ISSYMREF)
return unlink(git_path(refname));
item = path_list_append(refname, branches->branches);
item->util = xmalloc(20);
hashcpy(item->util, sha1);
return 0;
}
@@ -316,8 +351,9 @@ static int rm(int argc, const char **argv)
};
struct remote *remote;
struct strbuf buf;
struct known_remotes known_remotes = { NULL, NULL };
struct path_list branches = { NULL, 0, 0, 1 };
struct branches_for_remote cb_data = { NULL, &branches };
struct branches_for_remote cb_data = { NULL, &branches, &known_remotes };
int i;
if (argc != 2)
@@ -327,6 +363,9 @@ static int rm(int argc, const char **argv)
if (!remote)
die("No such remote: %s", argv[1]);
known_remotes.to_delete = remote;
for_each_remote(add_known_remote, &known_remotes);
strbuf_init(&buf, 0);
strbuf_addf(&buf, "remote.%s", remote->name);
if (git_config_rename_section(buf.buf, NULL) < 1)
@@ -355,9 +394,7 @@ static int rm(int argc, const char **argv)
* the branches one by one, since for_each_ref() relies on cached
* refs, which are invalidated when deleting a branch.
*/
strbuf_reset(&buf);
strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
cb_data.prefix = buf.buf;
cb_data.remote = remote;
i = for_each_ref(add_branch_for_removal, &cb_data);
strbuf_release(&buf);
@@ -422,27 +459,10 @@ static int show_or_prune(int argc, const char **argv, int prune)
states.remote->name);
if (prune) {
struct strbuf buf;
int prefix_len;
strbuf_init(&buf, 0);
if (states.remote->fetch_refspec_nr == 1 &&
states.remote->fetch->pattern &&
!strcmp(states.remote->fetch->src,
states.remote->fetch->dst))
/* handle --mirror remote */
strbuf_addstr(&buf, "refs/heads/");
else
strbuf_addf(&buf, "refs/remotes/%s/", *argv);
prefix_len = buf.len;
for (i = 0; i < states.stale.nr; i++) {
strbuf_setlen(&buf, prefix_len);
strbuf_addstr(&buf, states.stale.items[i].path);
result |= delete_ref(buf.buf, NULL);
const char *refname = states.stale.items[i].util;
result |= delete_ref(refname, NULL);
}
strbuf_release(&buf);
goto cleanup_states;
}
@@ -514,7 +534,7 @@ struct remote_group {
struct path_list *list;
} remote_group;
static int get_remote_group(const char *key, const char *value)
static int get_remote_group(const char *key, const char *value, void *cb)
{
if (!prefixcmp(key, "remotes.") &&
!strcmp(key + 8, remote_group.name)) {
@@ -546,7 +566,7 @@ static int update(int argc, const char **argv)
remote_group.list = &list;
for (i = 1; i < argc; i++) {
remote_group.name = argv[i];
result = git_config(get_remote_group);
result = git_config(get_remote_group, NULL);
}
if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default"))

View File

@@ -339,7 +339,7 @@ tail_optimization:
return write_rr(rr, fd);
}
static int git_rerere_config(const char *var, const char *value)
static int git_rerere_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "gc.rerereresolved"))
cutoff_resolve = git_config_int(var, value);
@@ -348,7 +348,7 @@ static int git_rerere_config(const char *var, const char *value)
else if (!strcmp(var, "rerere.enabled"))
rerere_enabled = git_config_bool(var, value);
else
return git_default_config(var, value);
return git_default_config(var, value, cb);
return 0;
}
@@ -376,7 +376,7 @@ static int setup_rerere(struct path_list *merge_rr)
{
int fd;
git_config(git_rerere_config);
git_config(git_rerere_config, NULL);
if (!is_rerere_enabled())
return -1;

View File

@@ -49,13 +49,14 @@ static inline int is_merge(void)
return !access(git_path("MERGE_HEAD"), F_OK);
}
static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
static int reset_index_file(const unsigned char *sha1, int is_hard_reset, int quiet)
{
int i = 0;
const char *args[6];
args[i++] = "read-tree";
args[i++] = "-v";
if (!quiet)
args[i++] = "-v";
args[i++] = "--reset";
if (is_hard_reset)
args[i++] = "-u";
@@ -182,11 +183,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
OPT_SET_INT(0, "hard", &reset_type,
"reset HEAD, index and working tree", HARD),
OPT_BOOLEAN('q', NULL, &quiet,
"disable showing new HEAD in hard reset"),
"disable showing new HEAD in hard reset and progress message"),
OPT_END()
};
git_config(git_default_config);
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
@@ -231,7 +232,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (is_merge() || read_cache() < 0 || unmerged_cache())
die("Cannot do a soft reset in the middle of a merge.");
}
else if (reset_index_file(sha1, (reset_type == HARD)))
else if (reset_index_file(sha1, (reset_type == HARD), quiet))
die("Could not reset index file to revision '%s'.", rev);
/* Any resets update HEAD to the head being switched to,

View File

@@ -10,6 +10,7 @@
#include "list-objects.h"
#include "builtin.h"
#include "log-tree.h"
#include "graph.h"
/* bits #0-15 in revision.h */
@@ -58,26 +59,31 @@ static const char *header_prefix;
static void finish_commit(struct commit *commit);
static void show_commit(struct commit *commit)
{
graph_show_commit(revs.graph);
if (show_timestamp)
printf("%lu ", commit->date);
if (header_prefix)
fputs(header_prefix, stdout);
if (commit->object.flags & BOUNDARY)
putchar('-');
else if (commit->object.flags & UNINTERESTING)
putchar('^');
else if (revs.left_right) {
if (commit->object.flags & SYMMETRIC_LEFT)
putchar('<');
else
putchar('>');
if (!revs.graph) {
if (commit->object.flags & BOUNDARY)
putchar('-');
else if (commit->object.flags & UNINTERESTING)
putchar('^');
else if (revs.left_right) {
if (commit->object.flags & SYMMETRIC_LEFT)
putchar('<');
else
putchar('>');
}
}
if (revs.abbrev_commit && revs.abbrev)
fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
stdout);
else
fputs(sha1_to_hex(commit->object.sha1), stdout);
if (revs.parents) {
if (revs.print_parents) {
struct commit_list *parents = commit->parents;
while (parents) {
printf(" %s", sha1_to_hex(parents->item->object.sha1));
@@ -96,9 +102,48 @@ static void show_commit(struct commit *commit)
pretty_print_commit(revs.commit_format, commit,
&buf, revs.abbrev, NULL, NULL,
revs.date_mode, 0);
if (buf.len)
printf("%s%c", buf.buf, hdr_termination);
if (revs.graph) {
if (buf.len) {
if (revs.commit_format != CMIT_FMT_ONELINE)
graph_show_oneline(revs.graph);
graph_show_commit_msg(revs.graph, &buf);
/*
* Add a newline after the commit message.
*
* Usually, this newline produces a blank
* padding line between entries, in which case
* we need to add graph padding on this line.
*
* However, the commit message may not end in a
* newline. In this case the newline simply
* ends the last line of the commit message,
* and we don't need any graph output. (This
* always happens with CMIT_FMT_ONELINE, and it
* happens with CMIT_FMT_USERFORMAT when the
* format doesn't explicitly end in a newline.)
*/
if (buf.len && buf.buf[buf.len - 1] == '\n')
graph_show_padding(revs.graph);
putchar('\n');
} else {
/*
* If the message buffer is empty, just show
* the rest of the graph output for this
* commit.
*/
if (graph_show_remainder(revs.graph))
putchar('\n');
}
} else {
if (buf.len)
printf("%s%c", buf.buf, hdr_termination);
}
strbuf_release(&buf);
} else {
if (graph_show_remainder(revs.graph))
putchar('\n');
}
maybe_flush_or_die(stdout, "stdout");
finish_commit(commit);
@@ -546,7 +591,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
int bisect_find_all = 0;
int quiet = 0;
git_config(git_default_config);
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
revs.abbrev = 0;
revs.commit_format = CMIT_FMT_UNSPECIFIED;

View File

@@ -94,6 +94,14 @@ static void show(const char *arg)
puts(arg);
}
/* Like show(), but with a negation prefix according to type */
static void show_with_type(int type, const char *arg)
{
if (type != show_type)
putchar('^');
show(arg);
}
/* Output a revision, only if filter allows it */
static void show_rev(int type, const unsigned char *sha1, const char *name)
{
@@ -101,8 +109,6 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
return;
def = NULL;
if (type != show_type)
putchar('^');
if (symbolic && name) {
if (symbolic == SHOW_SYMBOLIC_FULL) {
unsigned char discard[20];
@@ -119,20 +125,20 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
*/
break;
case 1: /* happy */
show(full);
show_with_type(type, full);
break;
default: /* ambiguous */
error("refname '%s' is ambiguous", name);
break;
}
} else {
show(name);
show_with_type(type, name);
}
}
else if (abbrev)
show(find_unique_abbrev(sha1, abbrev));
show_with_type(type, find_unique_abbrev(sha1, abbrev));
else
show(sha1_to_hex(sha1));
show_with_type(type, sha1_to_hex(sha1));
}
/* Output a flag, only if filter allows it. */
@@ -381,7 +387,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
return cmd_parseopt(argc - 1, argv + 1, prefix);
prefix = setup_git_directory();
git_config(git_default_config);
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

View File

@@ -269,7 +269,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
const char *message, *encoding;
const char *defmsg = xstrdup(git_path("MERGE_MSG"));
git_config(git_default_config);
git_config(git_default_config, NULL);
me = action == REVERT ? "revert" : "cherry-pick";
setenv(GIT_REFLOG_ACTION, me, 0);
parse_args(argc, argv);

View File

@@ -144,7 +144,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
const char **pathspec;
char *seen;
git_config(git_default_config);
git_config(git_default_config, NULL);
newfd = hold_locked_index(&lock_file, 1);

View File

@@ -537,9 +537,17 @@ static void verify_remote_names(int nr_heads, const char **heads)
int i;
for (i = 0; i < nr_heads; i++) {
const char *local = heads[i];
const char *remote = strrchr(heads[i], ':');
remote = remote ? (remote + 1) : heads[i];
if (*local == '+')
local++;
/* A matching refspec is okay. */
if (remote == local && remote[1] == '\0')
continue;
remote = remote ? (remote + 1) : local;
switch (check_ref_format(remote)) {
case 0: /* ok */
case CHECK_REF_FORMAT_ONELEVEL:

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