Merge branch 'master' of git://repo.or.cz/alt-git

This commit is contained in:
Johannes Sixt
2008-05-27 08:40:36 +02:00
159 changed files with 4217 additions and 1014 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
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
@@ -11,10 +12,7 @@ MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
DOC_HTML=$(MAN_HTML)
ARTICLES = tutorial
ARTICLES += tutorial-2
ARTICLES += core-tutorial
ARTICLES += cvs-migration
ARTICLES = core-tutorial
ARTICLES += diffcore
ARTICLES += howto-index
ARTICLES += repository-layout

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

@@ -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,53 @@ 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 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.
* "gitweb" can read from a system-wide configuration file.
(internal)
@@ -54,6 +101,6 @@ this release, unless otherwise noted.
--
exec >/var/tmp/1
O=v1.5.5-56-g5f0734f
O=v1.5.6-rc0
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint

View File

@@ -523,8 +523,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 +662,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 +710,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 +831,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

@@ -8,7 +8,7 @@ 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 +1581,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
---------------------------

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,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

@@ -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
@@ -68,6 +68,11 @@ OPTIONS
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.

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

@@ -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

@@ -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

@@ -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

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

@@ -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

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

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,11 @@ 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.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.2/git.html[documentation for release 1.5.5.2]
* link:v1.5.4.5/git.html[documentation for release 1.5.4.5]

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,7 +19,7 @@ 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
linkgit:gittutorial[7][tutorial introduction to git] and the
link:glossary.html[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,13 @@ 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],
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,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
@@ -394,7 +405,7 @@ link:glossary.html[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.
@@ -404,3 +415,14 @@ link:howto-index.html[howtos].
For git developers, the link:core-tutorial.html[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],
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,15 @@ 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],
link:everyday.html[Everyday git],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[7] suite.

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".

View File

@@ -115,7 +115,7 @@ Sample usage
------------
struct commit *commit;
struct git_graph *graph = graph_init();
struct git_graph *graph = graph_init(opts);
while ((commit = get_revision(opts)) != NULL) {
graph_update(graph, commit);

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

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
@@ -483,6 +482,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

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

@@ -100,15 +100,16 @@ static void update_callback(struct diff_queue_struct *q,
case DIFF_STATUS_UNMERGED:
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
if (add_file_to_cache(path, data->flags & ADD_FILES_VERBOSE)) {
if (!(data->flags & ADD_FILES_IGNORE_ERRORS))
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 (data->flags & ADD_FILES_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;
}
@@ -206,13 +207,13 @@ static struct option builtin_add_options[] = {
OPT_END(),
};
static int add_config(const char *var, const char *value)
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);
return git_default_config(var, value, cb);
}
int cmd_add(int argc, const char **argv, const char *prefix)
@@ -221,6 +222,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int i, newfd;
const char **pathspec;
struct dir_struct dir;
int flags;
argc = parse_options(argc, argv, builtin_add_options,
builtin_add_usage, 0);
@@ -229,22 +231,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (add_interactive)
exit(interactive_add(argc, argv, prefix));
git_config(add_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) {
int flags = 0;
const char **pathspec;
if (read_cache() < 0)
die("index file corrupt");
pathspec = get_pathspec(prefix, argv);
if (verbose)
flags |= ADD_FILES_VERBOSE;
if (ignore_add_errors)
flags |= ADD_FILES_IGNORE_ERRORS;
exit_status = add_files_to_cache(prefix, pathspec, flags);
goto finish;
}
@@ -263,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");
@@ -287,7 +275,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
for (i = 0; i < dir.nr; i++)
if (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;

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

@@ -236,6 +236,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()) {
@@ -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

550
builtin-clone.c Normal file
View File

@@ -0,0 +1,550 @@
/*
* 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]);
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

@@ -806,7 +806,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;
@@ -860,7 +860,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)
@@ -869,7 +869,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[] =
@@ -897,7 +897,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

@@ -21,7 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
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))

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

@@ -234,7 +234,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
*/
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;

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

@@ -635,7 +635,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);
@@ -647,7 +647,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;
@@ -657,7 +657,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;

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,117 @@ 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] [--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 *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, "--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,7 @@ 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;
if (add_file_to_cache(path, verbose))
if (add_file_to_cache(path, verbose ? ADD_CACHE_VERBOSE : 0))
die("updating index entries failed");
}

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 {
@@ -67,7 +68,7 @@ static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
static int keep_unreachable, include_tag;
static int keep_unreachable, unpack_unreachable, include_tag;
static int local;
static int incremental;
static int allow_ofs_delta;
@@ -1759,7 +1760,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);
@@ -1812,7 +1813,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)
@@ -1946,6 +1947,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;
@@ -1980,6 +2007,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)
@@ -2004,7 +2033,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;
@@ -2114,6 +2143,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;
@@ -2179,6 +2212,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

@@ -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,7 +200,7 @@ 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);
}
@@ -514,7 +514,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 +546,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

@@ -186,7 +186,7 @@ int cmd_reset(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, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);

View File

@@ -65,15 +65,18 @@ static void show_commit(struct commit *commit)
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),
@@ -588,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:

View File

@@ -533,7 +533,7 @@ static void append_one_rev(const char *av)
die("bad sha1 reference %s", av);
}
static int git_show_branch_config(const char *var, const char *value)
static int git_show_branch_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "showbranch.default")) {
if (!value)
@@ -547,7 +547,7 @@ static int git_show_branch_config(const char *var, const char *value)
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -611,7 +611,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int reflog = 0;
const char *reflog_base = NULL;
git_config(git_show_branch_config);
git_config(git_show_branch_config, NULL);
/* If nothing is specified, try the default first */
if (ac == 1 && default_num) {

View File

@@ -35,7 +35,7 @@ int cmd_symbolic_ref(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, options, git_symbolic_ref_usage, 0);
if (msg &&!*msg)
die("Refusing to perform update with empty message");

View File

@@ -256,7 +256,7 @@ static void set_signingkey(const char *value)
die("signing key value too long (%.10s...)", value);
}
static int git_tag_config(const char *var, const char *value)
static int git_tag_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "user.signingkey")) {
if (!value)
@@ -265,7 +265,7 @@ static int git_tag_config(const char *var, const char *value)
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static void write_tag_body(int fd, const unsigned char *sha1)
@@ -408,7 +408,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_END()
};
git_config(git_tag_config);
git_config(git_tag_config, NULL);
argc = parse_options(argc, argv, options, git_tag_usage, 0);

View File

@@ -493,7 +493,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
int i;
unsigned char sha1[20];
git_config(git_default_config);
git_config(git_default_config, NULL);
quiet = !isatty(2);

View File

@@ -567,7 +567,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
int lock_error = 0;
struct lock_file *lock_file;
git_config(git_default_config);
git_config(git_default_config, NULL);
/* We can't free this memory, it becomes part of a linked list parsed atexit() */
lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -593,6 +593,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
refresh_flags |= REFRESH_QUIET;
continue;
}
if (!strcmp(path, "--ignore-submodules")) {
refresh_flags |= REFRESH_IGNORE_SUBMODULES;
continue;
}
if (!strcmp(path, "--add")) {
allow_add = 1;
continue;

View File

@@ -22,7 +22,7 @@ int cmd_update_ref(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, options, git_update_ref_usage, 0);
if (msg && !*msg)
die("Refusing to perform update with empty message.");

View File

@@ -55,7 +55,7 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix)
int no_more_options = 0;
int nothing_done = 1;
git_config(git_default_config);
git_config(git_default_config, NULL);
while (1 < argc) {
if (!no_more_options && argv[1][0] == '-') {
if (!strcmp("-v", argv[1]))

View File

@@ -90,7 +90,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
git_config(git_default_config);
git_config(git_default_config, NULL);
if (argc == 1)
usage(builtin_verify_tag_usage);

View File

@@ -18,7 +18,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
unsigned char sha1[20];
const char *me = "git-write-tree";
git_config(git_default_config);
git_config(git_default_config, NULL);
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--missing-ok"))

View File

@@ -9,6 +9,7 @@ extern const char git_usage_string[];
extern void list_common_cmds_help(void);
extern void help_unknown_cmd(const char *cmd);
extern void prune_packed_objects(int);
extern int read_line_with_nul(char *buf, int size, FILE *file);
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
@@ -24,6 +25,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
extern int cmd_cherry(int argc, const char **argv, const char *prefix);
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
extern int cmd_clone(int argc, const char **argv, const char *prefix);
extern int cmd_clean(int argc, const char **argv, const char *prefix);
extern int cmd_commit(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);

32
cache.h
View File

@@ -261,8 +261,8 @@ static inline void remove_name_hash(struct cache_entry *ce)
#define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))
#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
#define add_to_cache(path, st, verbose) add_to_index(&the_index, (path), (st), (verbose))
#define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
@@ -317,6 +317,7 @@ extern char *get_graft_file(void);
extern int set_git_dir(const char *path);
extern const char *get_git_work_tree(void);
extern const char *read_gitfile_gently(const char *path);
extern void set_git_work_tree(const char *tree);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
@@ -329,6 +330,10 @@ extern const char *prefix_filename(const char *prefix, int len, const char *path
extern void verify_filename(const char *prefix, const char *name);
extern void verify_non_filename(const char *prefix, const char *name);
#define INIT_DB_QUIET 0x0001
extern int init_db(const char *template_dir, unsigned int flags);
#define alloc_nr(x) (((x)+16)*3/2)
/*
@@ -366,8 +371,11 @@ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int opt
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
extern int remove_index_entry_at(struct index_state *, int pos);
extern int remove_file_from_index(struct index_state *, const char *path);
extern int add_to_index(struct index_state *, const char *path, struct stat *, int verbose);
extern int add_file_to_index(struct index_state *, const char *path, int verbose);
#define ADD_CACHE_VERBOSE 1
#define ADD_CACHE_PRETEND 2
#define ADD_CACHE_IGNORE_ERRORS 4
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
@@ -388,6 +396,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
#define REFRESH_QUIET 0x0004 /* be quiet about it */
#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
#define REFRESH_IGNORE_SUBMODULES 0x0008 /* ignore submodules */
extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen);
struct lock_file {
@@ -398,6 +407,7 @@ struct lock_file {
char filename[PATH_MAX];
};
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
extern int commit_lock_file(struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
@@ -521,6 +531,7 @@ extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type,
extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
@@ -614,6 +625,7 @@ extern struct alternate_object_database {
char base[FLEX_ARRAY]; /* more */
} *alt_odb_list;
extern void prepare_alt_odb(void);
extern void add_to_alternates_file(const char *reference);
struct pack_window {
struct pack_window *next;
@@ -711,10 +723,10 @@ extern int matches_pack_name(struct packed_git *p, const char *name);
/* Dumb servers support */
extern int update_server_info(int);
typedef int (*config_fn_t)(const char *, const char *);
extern int git_default_config(const char *, const char *);
extern int git_config_from_file(config_fn_t fn, const char *);
extern int git_config(config_fn_t fn);
typedef int (*config_fn_t)(const char *, const char *, void *);
extern int git_default_config(const char *, const char *, void *);
extern int git_config_from_file(config_fn_t fn, const char *, void *);
extern int git_config(config_fn_t fn, void *);
extern int git_parse_long(const char *, long *);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
@@ -726,7 +738,7 @@ extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_rename_section(const char *, const char *);
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value);
extern int check_repository_format_version(const char *var, const char *value, void *cb);
extern int git_env_bool(const char *, int);
extern int git_config_system(void);
extern int git_config_global(void);
@@ -782,8 +794,6 @@ extern int convert_to_git(const char *path, const char *src, size_t len,
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
/* add */
#define ADD_FILES_VERBOSE 01
#define ADD_FILES_IGNORE_ERRORS 02
/*
* return 0 if success, 1 - if addition of a file failed and
* ADD_FILES_IGNORE_ERRORS was specified in flags

View File

@@ -145,14 +145,14 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty)
return 0;
}
int git_color_default_config(const char *var, const char *value)
int git_color_default_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "color.ui")) {
git_use_color_default = git_config_colorbool(var, value, -1);
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static int color_vfprintf(FILE *fp, const char *color, const char *fmt,

View File

@@ -13,7 +13,7 @@ extern int git_use_color_default;
/*
* Use this instead of git_default_config if you need the value of color.ui.
*/
int git_color_default_config(const char *var, const char *value);
int git_color_default_config(const char *var, const char *value, void *cb);
int git_config_colorbool(const char *var, const char *value, int stdout_is_tty);
void color_parse(const char *var, const char *value, char *dst);

View File

@@ -111,7 +111,7 @@ static inline int iskeychar(int c)
return isalnum(c) || c == '-';
}
static int get_value(config_fn_t fn, char *name, unsigned int len)
static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
{
int c;
char *value;
@@ -139,7 +139,7 @@ static int get_value(config_fn_t fn, char *name, unsigned int len)
if (!value)
return -1;
}
return fn(name, value);
return fn(name, value, data);
}
static int get_extended_base_var(char *name, int baselen, int c)
@@ -197,7 +197,7 @@ static int get_base_var(char *name)
}
}
static int git_parse_file(config_fn_t fn)
static int git_parse_file(config_fn_t fn, void *data)
{
int comment = 0;
int baselen = 0;
@@ -228,7 +228,7 @@ static int git_parse_file(config_fn_t fn)
if (!isalpha(c))
break;
var[baselen] = tolower(c);
if (get_value(fn, var, baselen+1) < 0)
if (get_value(fn, data, var, baselen+1) < 0)
break;
}
die("bad config file line %d in %s", config_linenr, config_file_name);
@@ -332,7 +332,7 @@ int git_config_string(const char **dest, const char *var, const char *value)
return 0;
}
int git_default_config(const char *var, const char *value)
int git_default_config(const char *var, const char *value, void *dummy)
{
/* This needs a better name */
if (!strcmp(var, "core.filemode")) {
@@ -516,7 +516,7 @@ int git_default_config(const char *var, const char *value)
return 0;
}
int git_config_from_file(config_fn_t fn, const char *filename)
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
{
int ret;
FILE *f = fopen(filename, "r");
@@ -527,7 +527,7 @@ int git_config_from_file(config_fn_t fn, const char *filename)
config_file_name = filename;
config_linenr = 1;
config_file_eof = 0;
ret = git_parse_file(fn);
ret = git_parse_file(fn, data);
fclose(f);
config_file_name = NULL;
}
@@ -565,7 +565,7 @@ int git_config_global(void)
return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
}
int git_config(config_fn_t fn)
int git_config(config_fn_t fn, void *data)
{
int ret = 0;
char *repo_config = NULL;
@@ -578,7 +578,8 @@ int git_config(config_fn_t fn)
filename = getenv(CONFIG_ENVIRONMENT);
if (!filename) {
if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
ret += git_config_from_file(fn, git_etc_gitconfig());
ret += git_config_from_file(fn, git_etc_gitconfig(),
data);
home = getenv("HOME");
filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!filename)
@@ -588,11 +589,11 @@ int git_config(config_fn_t fn)
if (git_config_global() && home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
if (!access(user_config, R_OK))
ret = git_config_from_file(fn, user_config);
ret = git_config_from_file(fn, user_config, data);
free(user_config);
}
ret += git_config_from_file(fn, filename);
ret += git_config_from_file(fn, filename, data);
free(repo_config);
return ret;
}
@@ -622,7 +623,7 @@ static int matches(const char* key, const char* value)
!regexec(store.value_regex, value, 0, NULL, 0)));
}
static int store_aux(const char* key, const char* value)
static int store_aux(const char* key, const char* value, void *cb)
{
const char *ep;
size_t section_len;
@@ -951,7 +952,7 @@ int git_config_set_multivar(const char* key, const char* value,
* As a side effect, we make sure to transform only a valid
* existing config file.
*/
if (git_config_from_file(store_aux, config_filename)) {
if (git_config_from_file(store_aux, config_filename, NULL)) {
error("invalid config file %s", config_filename);
free(store.key);
if (store.value_regex != NULL) {

View File

@@ -360,7 +360,8 @@ static char *git_proxy_command;
static const char *rhost_name;
static int rhost_len;
static int git_proxy_command_options(const char *var, const char *value)
static int git_proxy_command_options(const char *var, const char *value,
void *cb)
{
if (!strcmp(var, "core.gitproxy")) {
const char *for_pos;
@@ -404,7 +405,7 @@ static int git_proxy_command_options(const char *var, const char *value)
return 0;
}
return git_default_config(var, value);
return git_default_config(var, value, cb);
}
static int git_use_proxy(const char *host)
@@ -412,7 +413,7 @@ static int git_use_proxy(const char *host)
rhost_name = host;
rhost_len = strlen(host);
git_proxy_command = getenv("GIT_PROXY_COMMAND");
git_config(git_proxy_command_options);
git_config(git_proxy_command_options, NULL);
rhost_name = NULL;
return (git_proxy_command && *git_proxy_command);
}

View File

@@ -32,56 +32,6 @@ die() {
exit 1
}
# Fix some commands on Windows
case $(uname -s) in
*MINGW*)
# Windows has its own (incompatible) find
find () {
/usr/bin/find "$@"
}
# need an emulation of cpio
cpio() {
case "$1" in
-pumd) cp_arg=-pr;;
-pumdl) cp_arg=-lr;;
*) die "cpio $1 unexpected";;
esac
# copy only files and empty directories
prev=
while read f; do
if test -d "$f"; then
# here we assume that directories are listed after
# its files (aka 'find -depth'), hence, a directory
# that is not empty will be a leading sub-string
# of the preceding entry
case "$prev" in
"$f"/* ) ;;
*) echo "$f";;
esac
else
echo "$f"
fi
prev="$f"
done |
xargs --no-run-if-empty \
cp $cp_arg --target-directory="$2" --parents
}
# pwd must return a path with a drive letter
bin_pwd() {
# there are no symlinks to resolve: /bin/pwd is not needed
builtin pwd -W
}
pwd() {
builtin pwd -W
}
;;
*)
bin_pwd() {
/bin/pwd
}
;;
esac
usage() {
exec "$0" -h
}
@@ -90,7 +40,7 @@ eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)
get_repo_base() {
(
cd "$(bin_pwd)" &&
cd "`/bin/pwd`" &&
cd "$1" || cd "$1.git" &&
{
cd .git

View File

@@ -136,6 +136,7 @@ sub parse_config ($$$$) {
local $ENV{GIT_DIR} = shift;
my $br = shift;
my $fn = shift;
return unless git_value('rev-list','--max-count=1',$br,'--',$fn);
info "Loading $br:$fn";
open(I,'-|','git','cat-file','blob',"$br:$fn");
my $section = '';
@@ -225,14 +226,12 @@ sub load_diff ($) {
local $/ = "\0";
my %this_diff;
if ($base =~ /^0{40}$/) {
open(T,'-|','git','ls-tree',
'-r','--name-only','-z',
$new) or return undef;
while (<T>) {
chop;
$this_diff{$_} = 'A';
}
close T or return undef;
# Don't load the diff at all; we are making the
# branch and have no base to compare to in this
# case. A file level ACL makes no sense in this
# context. Having an empty diff will allow the
# branch creation.
#
} else {
open(T,'-|','git','diff-tree',
'-r','--name-status','-z',
@@ -260,6 +259,7 @@ deny "Refusing funny ref $ref" unless $ref =~ s,^refs/,,;
deny "Bad old value $old" unless $old =~ /^[a-z0-9]{40}$/;
deny "Bad new value $new" unless $new =~ /^[a-z0-9]{40}$/;
deny "Cannot determine who you are." unless $this_user;
grant "No change requested." if $old eq $new;
$repository_name = File::Spec->rel2abs($git_dir);
$repository_name =~ m,/([^/]+)(?:\.git|/\.git)$,;

View File

@@ -323,7 +323,7 @@ static struct convert_driver {
char *clean;
} *user_convert, **user_convert_tail;
static int read_convert_config(const char *var, const char *value)
static int read_convert_config(const char *var, const char *value, void *cb)
{
const char *ep, *name;
int namelen;
@@ -385,7 +385,7 @@ static void setup_convert_check(struct git_attr_check *check)
attr_ident = git_attr("ident", 5);
attr_filter = git_attr("filter", 6);
user_convert_tail = &user_convert;
git_config(read_convert_config);
git_config(read_convert_config, NULL);
}
check[0].attr = attr_crlf;
check[1].attr = attr_ident;

View File

@@ -306,7 +306,7 @@ struct daemon_service {
static struct daemon_service *service_looking_at;
static int service_enabled;
static int git_daemon_config(const char *var, const char *value)
static int git_daemon_config(const char *var, const char *value, void *cb)
{
if (!prefixcmp(var, "daemon.") &&
!strcmp(var + 7, service_looking_at->config_name)) {
@@ -356,7 +356,7 @@ static int run_service(struct interp *itable, struct daemon_service *service)
if (service->overridable) {
service_looking_at = service;
service_enabled = -1;
git_config(git_daemon_config);
git_config(git_daemon_config, NULL);
if (0 <= service_enabled)
enabled = service_enabled;
}

17
diff.c
View File

@@ -129,7 +129,7 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v
* never be affected by the setting of diff.renames
* the user happens to have in the configuration file.
*/
int git_diff_ui_config(const char *var, const char *value)
int git_diff_ui_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "diff.renamelimit")) {
diff_rename_limit_default = git_config_int(var, value);
@@ -166,10 +166,10 @@ int git_diff_ui_config(const char *var, const char *value)
return parse_lldiff_command(var, ep, value);
}
return git_diff_basic_config(var, value);
return git_diff_basic_config(var, value, cb);
}
int git_diff_basic_config(const char *var, const char *value)
int git_diff_basic_config(const char *var, const char *value, void *cb)
{
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
int slot = parse_diff_color_slot(var, 11);
@@ -190,7 +190,7 @@ int git_diff_basic_config(const char *var, const char *value)
}
}
return git_color_default_config(var, value);
return git_color_default_config(var, value, cb);
}
static char *quote_two(const char *one, const char *two)
@@ -2496,6 +2496,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_SET(options, ALLOW_EXTERNAL);
else if (!strcmp(arg, "--no-ext-diff"))
DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
else if (!strcmp(arg, "--ignore-submodules"))
DIFF_OPT_SET(options, IGNORE_SUBMODULES);
/* misc options */
else if (!strcmp(arg, "-z"))
@@ -3355,6 +3357,9 @@ void diff_addremove(struct diff_options *options,
char concatpath[PATH_MAX];
struct diff_filespec *one, *two;
if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode))
return;
/* This may look odd, but it is a preparation for
* feeding "there are unchanged files which should
* not produce diffs, but when you are doing copy
@@ -3399,6 +3404,10 @@ void diff_change(struct diff_options *options,
char concatpath[PATH_MAX];
struct diff_filespec *one, *two;
if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode)
&& S_ISGITLINK(new_mode))
return;
if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
unsigned tmp;
const unsigned char *tmp_c;

5
diff.h
View File

@@ -63,6 +63,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
#define DIFF_OPT_REVERSE_DIFF (1 << 15)
#define DIFF_OPT_CHECK_FAILED (1 << 16)
#define DIFF_OPT_RELATIVE_NAME (1 << 17)
#define DIFF_OPT_IGNORE_SUBMODULES (1 << 18)
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
@@ -181,8 +182,8 @@ extern void diff_unmerge(struct diff_options *,
#define DIFF_SETUP_USE_CACHE 2
#define DIFF_SETUP_USE_SIZE_CACHE 4
extern int git_diff_basic_config(const char *var, const char *value);
extern int git_diff_ui_config(const char *var, const char *value);
extern int git_diff_basic_config(const char *var, const char *value, void *cb);
extern int git_diff_ui_config(const char *var, const char *value, void *cb);
extern int diff_use_color_default;
extern void diff_setup(struct diff_options *);
extern int diff_opt_parse(struct diff_options *, const char **, int);

View File

@@ -44,7 +44,7 @@ enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
/* This is set by setup_git_dir_gently() and/or git_default_config() */
char *git_work_tree_cfg;
static const char *work_tree;
static char *work_tree;
static const char *git_dir;
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
@@ -86,10 +86,26 @@ const char *get_git_dir(void)
return git_dir;
}
static int git_work_tree_initialized;
/*
* Note. This works only before you used a work tree. This was added
* primarily to support git-clone to work in a new repository it just
* created, and is not meant to flip between different work trees.
*/
void set_git_work_tree(const char *new_work_tree)
{
if (is_bare_repository_cfg >= 0)
die("cannot set work tree after initialization");
git_work_tree_initialized = 1;
free(work_tree);
work_tree = xstrdup(make_absolute_path(new_work_tree));
is_bare_repository_cfg = 0;
}
const char *get_git_work_tree(void)
{
static int initialized = 0;
if (!initialized) {
if (!git_work_tree_initialized) {
work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
/* core.bare = true overrides implicit and config work tree */
if (!work_tree && is_bare_repository_cfg < 1) {
@@ -99,7 +115,7 @@ const char *get_git_work_tree(void)
work_tree = xstrdup(make_absolute_path(git_path(work_tree)));
} else if (work_tree)
work_tree = xstrdup(make_absolute_path(work_tree));
initialized = 1;
git_work_tree_initialized = 1;
if (work_tree)
is_bare_repository_cfg = 0;
}

View File

@@ -2352,7 +2352,7 @@ static void import_marks(const char *input_file)
fclose(f);
}
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.depth")) {
max_depth = git_config_int(k, v);
@@ -2370,7 +2370,7 @@ static int git_pack_config(const char *k, const char *v)
pack_compression_seen = 1;
return 0;
}
return git_default_config(k, v);
return git_default_config(k, v, cb);
}
static const char fast_import_usage[] =
@@ -2381,7 +2381,7 @@ int main(int argc, const char **argv)
unsigned int i, show_stats = 1;
setup_git_directory();
git_config(git_pack_config);
git_config(git_pack_config, NULL);
if (!pack_compression_seen && core_compression_seen)
pack_compression_level = core_compression_level;

View File

@@ -63,40 +63,40 @@ bisect_autostart() {
bisect_start() {
#
# Verify HEAD. If we were bisecting before this, reset to the
# top-of-line master first!
# Verify HEAD.
#
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
die "Bad HEAD - I need a HEAD"
#
# Check that we either already have BISECT_START, or that the
# branches bisect, new-bisect don't exist, to not override them.
#
test -s "$GIT_DIR/BISECT_START" ||
if git show-ref --verify -q refs/heads/bisect ||
git show-ref --verify -q refs/heads/new-bisect; then
die 'The branches "bisect" and "new-bisect" must not exist.'
fi
start_head=''
case "$head" in
refs/heads/bisect)
branch=`cat "$GIT_DIR/BISECT_START"`
git checkout $branch || exit
;;
refs/heads/*|$_x40)
# This error message should only be triggered by cogito usage,
# and cogito users should understand it relates to cg-seek.
[ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
start_head="${head#refs/heads/}"
;;
*)
die "Bad HEAD - strange symbolic ref"
;;
esac
#
# Get rid of any old bisect state
# Check if we are bisecting.
#
start_head=''
if test -s "$GIT_DIR/BISECT_START"
then
# Reset to the rev from where we started.
start_head=$(cat "$GIT_DIR/BISECT_START")
git checkout "$start_head" || exit
else
# Get rev from where we start.
case "$head" in
refs/heads/*|$_x40)
# This error message should only be triggered by
# cogito usage, and cogito users should understand
# it relates to cg-seek.
[ -s "$GIT_DIR/head-name" ] &&
die "won't bisect on seeked tree"
start_head="${head#refs/heads/}"
;;
*)
die "Bad HEAD - strange symbolic ref"
;;
esac
fi
#
# Get rid of any old bisect state.
#
bisect_clean_state
@@ -118,7 +118,7 @@ bisect_start() {
break
;;
*)
rev=$(git rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
rev=$(git rev-parse -q --verify "$arg^{commit}") || {
test $has_double_dash -eq 1 &&
die "'$arg' does not appear to be a valid revision"
break
@@ -133,11 +133,29 @@ bisect_start() {
esac
done
sq "$@" >"$GIT_DIR/BISECT_NAMES"
test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START"
eval "$eval"
echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
#
# Change state.
# In case of mistaken revs or checkout error, or signals received,
# "bisect_auto_next" below may exit or misbehave.
# We have to trap this to be able to clean up using
# "bisect_clean_state".
#
trap 'bisect_clean_state' 0
trap 'exit 255' 1 2 3 15
#
# Write new start state.
#
sq "$@" >"$GIT_DIR/BISECT_NAMES" &&
echo "$start_head" >"$GIT_DIR/BISECT_START" &&
eval "$eval" &&
echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
#
# Check if we can proceed to the next bisect state.
#
bisect_auto_next
trap '-' 0
}
bisect_write() {
@@ -149,9 +167,9 @@ bisect_write() {
good|skip) tag="$state"-"$rev" ;;
*) die "Bad bisect_write argument: $state" ;;
esac
git update-ref "refs/bisect/$tag" "$rev"
git update-ref "refs/bisect/$tag" "$rev" || exit
echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
test -z "$nolog" && echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
test -n "$nolog" || echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
}
bisect_state() {
@@ -348,9 +366,7 @@ bisect_next() {
exit_if_skipped_commits "$bisect_rev"
echo "Bisecting: $bisect_nr revisions left to test after this"
git branch -D new-bisect 2> /dev/null
git checkout -q -b new-bisect "$bisect_rev" || exit
git branch -M new-bisect bisect
git checkout -q "$bisect_rev" || exit
git show-branch "$bisect_rev"
}
@@ -392,24 +408,22 @@ bisect_reset() {
*)
usage ;;
esac
if git checkout "$branch"; then
# Cleanup head-name if it got left by an old version of git-bisect
rm -f "$GIT_DIR/head-name"
rm -f "$GIT_DIR/BISECT_START"
bisect_clean_state
fi
git checkout "$branch" && bisect_clean_state
}
bisect_clean_state() {
# There may be some refs packed during bisection.
git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* refs/heads/bisect |
git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
while read ref hash
do
git update-ref -d $ref $hash
done
rm -f "$GIT_DIR/BISECT_START"
rm -f "$GIT_DIR/BISECT_LOG"
rm -f "$GIT_DIR/BISECT_NAMES"
rm -f "$GIT_DIR/BISECT_RUN"
# Cleanup head-name if it got left by an old version of git-bisect
rm -f "$GIT_DIR/head-name"
}
bisect_replay () {

View File

@@ -8,9 +8,9 @@ use File::Basename qw(basename dirname);
use File::Spec;
use Git;
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w);
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w, $opt_W);
getopts('uhPpvcfam:d:w:');
getopts('uhPpvcfam:d:w:W');
$opt_h && usage();
@@ -20,7 +20,7 @@ die "Need at least one commit identifier!" unless @ARGV;
my $repo = Git->repository();
$opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
if ($opt_w) {
if ($opt_w || $opt_W) {
# Remember where GIT_DIR is before changing to CVS checkout
unless ($ENV{GIT_DIR}) {
# No GIT_DIR set. Figure it out for ourselves
@@ -30,7 +30,9 @@ if ($opt_w) {
}
# Make sure GIT_DIR is absolute
$ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
}
if ($opt_w) {
if (! -d $opt_w."/CVS" ) {
die "$opt_w is not a CVS checkout";
}
@@ -121,6 +123,15 @@ if ($parent) {
}
}
my $go_back_to = 0;
if ($opt_W) {
$opt_v && print "Resetting to $parent\n";
$go_back_to = `git symbolic-ref HEAD 2> /dev/null ||
git rev-parse HEAD` || die "Could not determine current branch";
system("git checkout -q $parent^0") && die "Could not check out $parent^0";
}
$opt_v && print "Applying to CVS commit $commit from parent $parent\n";
# grab the commit message
@@ -215,7 +226,8 @@ if (@canstatusfiles) {
my $basename = basename($name);
$basename = "no file " . $basename if (exists($added{$basename}));
chomp($basename);
$basename =~ s/^\s+//;
$basename =~ s/\s+$//;
if (!exists($fullname{$basename})) {
$fullname{$basename} = $name;
@@ -264,7 +276,11 @@ if ($dirty) {
}
print "Applying\n";
`GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
if ($opt_W) {
system("git checkout -q $commit^0") && die "cannot patch";
} else {
`GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
}
print "Patch applied successfully. Adding new files and directories to CVS\n";
my $dirtypatch = 0;
@@ -317,7 +333,9 @@ if ($dirtypatch) {
print "using a patch program. After applying the patch and resolving the\n";
print "problems you may commit using:";
print "\n cd \"$opt_w\"" if $opt_w;
print "\n $cmd\n\n";
print "\n $cmd\n";
print "\n git checkout $go_back_to\n" if $go_back_to;
print "\n";
exit(1);
}
@@ -337,6 +355,14 @@ if ($opt_c) {
# clean up
unlink(".cvsexportcommit.diff");
if ($opt_W) {
system("git checkout $go_back_to") && die "cannot move back to $go_back_to";
if (!($go_back_to =~ /^[0-9a-fA-F]{40}$/)) {
system("git symbolic-ref HEAD $go_back_to") &&
die "cannot move back to $go_back_to";
}
}
# CVS version 1.11.x and 1.12.x sleeps the wrong way to ensure the timestamp
# used by CVS and the one set by subsequence file modifications are different.
# If they are not different CVS will not detect changes.

View File

@@ -780,6 +780,7 @@ sub commit {
$xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
$xtag =~ tr/_/\./ if ( $opt_u );
$xtag =~ s/[\/]/$opt_s/g;
$xtag =~ s/\[//g;
system('git-tag', '-f', $xtag, $cid) == 0
or die "Cannot create tag $xtag: $!\n";

View File

@@ -21,6 +21,7 @@ use bytes;
use Fcntl;
use File::Temp qw/tempdir tempfile/;
use File::Path qw/rmtree/;
use File::Basename;
use Getopt::Long qw(:config require_order no_ignore_case);
@@ -86,6 +87,17 @@ my $methods = {
# $state holds all the bits of information the clients sends us that could
# potentially be useful when it comes to actually _doing_ something.
my $state = { prependdir => '' };
# Work is for managing temporary working directory
my $work =
{
state => undef, # undef, 1 (empty), 2 (with stuff)
workDir => undef,
index => undef,
emptyDir => undef,
tmpDir => undef
};
$log->info("--------------- STARTING -----------------");
my $usage =
@@ -189,6 +201,9 @@ while (<STDIN>)
$log->debug("Processing time : user=" . (times)[0] . " system=" . (times)[1]);
$log->info("--------------- FINISH -----------------");
chdir '/';
exit 0;
# Magic catchall method.
# This is the method that will handle all commands we haven't yet
# implemented. It simply sends a warning to the log file indicating a
@@ -487,7 +502,7 @@ sub req_add
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
# this is an "entries" line
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
$log->debug("/$filepart/1.$meta->{revision}//$kopts/");
print "/$filepart/1.$meta->{revision}//$kopts/\n";
# permissions
@@ -518,9 +533,26 @@ sub req_add
print "Checked-in $dirpart\n";
print "$filename\n";
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path($filename,"file",
$state->{entries}{$filename}{modified_filename});
print "/$filepart/0//$kopts/\n";
my $requestedKopts = $state->{opt}{k};
if(defined($requestedKopts))
{
$requestedKopts = "-k$requestedKopts";
}
else
{
$requestedKopts = "";
}
if( $kopts ne $requestedKopts )
{
$log->warn("Ignoring requested -k='$requestedKopts'"
. " for '$filename'; detected -k='$kopts' instead");
#TODO: Also have option to send warning to user?
}
$addcount++;
}
@@ -600,7 +632,7 @@ sub req_remove
print "Checked-in $dirpart\n";
print "$filename\n";
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
print "/$filepart/-1.$wrev//$kopts/\n";
$rmcount++;
@@ -770,6 +802,7 @@ sub req_co
argsplit("co");
my $module = $state->{args}[0];
$state->{module} = $module;
my $checkout_path = $module;
# use the user specified directory if we're given it
@@ -847,6 +880,7 @@ sub req_co
# Don't want to check out deleted files
next if ( $git->{filehash} eq "deleted" );
my $fullName = $git->{name};
( $git->{name}, $git->{dir} ) = filenamesplit($git->{name});
if (length($git->{dir}) && $git->{dir} ne './'
@@ -877,7 +911,7 @@ sub req_co
print $state->{CVSROOT} . "/$module/" . ( defined ( $git->{dir} ) and $git->{dir} ne "./" ? $git->{dir} . "/" : "" ) . "$git->{name}\n";
# this is an "entries" line
my $kopts = kopts_from_path($git->{name});
my $kopts = kopts_from_path($fullName,"sha1",$git->{filehash});
print "/$git->{name}/1.$git->{revision}//$kopts/\n";
# permissions
print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n";
@@ -1086,7 +1120,7 @@ sub req_update
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
# this is an "entries" line
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
$log->debug("/$filepart/1.$meta->{revision}//$kopts/");
print "/$filepart/1.$meta->{revision}//$kopts/\n";
@@ -1101,10 +1135,10 @@ sub req_update
$log->info("Updating '$filename'");
my ( $filepart, $dirpart ) = filenamesplit($meta->{name},1);
my $dir = tempdir( DIR => $TEMP_DIR, CLEANUP => 1 ) . "/";
my $mergeDir = setupTmpDir();
chdir $dir;
my $file_local = $filepart . ".mine";
my $mergedFile = "$mergeDir/$file_local";
system("ln","-s",$state->{entries}{$filename}{modified_filename}, $file_local);
my $file_old = $filepart . "." . $oldmeta->{revision};
transmitfile($oldmeta->{filehash}, { targetfile => $file_old });
@@ -1115,11 +1149,13 @@ sub req_update
$log->info("Merging $file_local, $file_old, $file_new");
print "M Merging differences between 1.$oldmeta->{revision} and 1.$meta->{revision} into $filename\n";
$log->debug("Temporary directory for merge is $dir");
$log->debug("Temporary directory for merge is $mergeDir");
my $return = system("git", "merge-file", $file_local, $file_old, $file_new);
$return >>= 8;
cleanupTmpDir();
if ( $return == 0 )
{
$log->info("Merged successfully");
@@ -1132,7 +1168,8 @@ sub req_update
print "Merged $dirpart\n";
$log->debug($state->{CVSROOT} . "/$state->{module}/$filename");
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path("$dirpart/$filepart",
"file",$mergedFile);
$log->debug("/$filepart/1.$meta->{revision}//$kopts/");
print "/$filepart/1.$meta->{revision}//$kopts/\n";
}
@@ -1148,7 +1185,8 @@ sub req_update
{
print "Merged $dirpart\n";
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path("$dirpart/$filepart",
"file",$mergedFile);
print "/$filepart/1.$meta->{revision}/+/$kopts/\n";
}
}
@@ -1168,13 +1206,11 @@ sub req_update
# transmit file, format is single integer on a line by itself (file
# size) followed by the file contents
# TODO : we should copy files in blocks
my $data = `cat $file_local`;
my $data = `cat $mergedFile`;
$log->debug("File size : " . length($data));
print length($data) . "\n";
print $data;
}
chdir "/";
}
}
@@ -1195,6 +1231,7 @@ sub req_ci
if ( $state->{method} eq 'pserver')
{
print "error 1 pserver access cannot commit\n";
cleanupWorkTree();
exit;
}
@@ -1202,6 +1239,7 @@ sub req_ci
{
$log->warn("file 'index' already exists in the git repository");
print "error 1 Index already exists in git repo\n";
cleanupWorkTree();
exit;
}
@@ -1209,31 +1247,20 @@ sub req_ci
my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
$updater->update();
my $tmpdir = tempdir ( DIR => $TEMP_DIR );
my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
$log->info("Lockless commit start, basing commit on '$tmpdir', index file is '$file_index'");
$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
$ENV{GIT_WORK_TREE} = ".";
$ENV{GIT_INDEX_FILE} = $file_index;
# Remember where the head was at the beginning.
my $parenthash = `git show-ref -s refs/heads/$state->{module}`;
chomp $parenthash;
if ($parenthash !~ /^[0-9a-f]{40}$/) {
print "error 1 pserver cannot find the current HEAD of module";
cleanupWorkTree();
exit;
}
chdir $tmpdir;
setupWorkTree($parenthash);
# populate the temporary index
system("git-read-tree", $parenthash);
unless ($? == 0)
{
die "Error running git-read-tree $state->{module} $file_index $!";
}
$log->info("Created index '$file_index' for head $state->{module} - exit status $?");
$log->info("Lockless commit start, basing commit on '$work->{workDir}', index file is '$work->{index}'");
$log->info("Created index '$work->{index}' for head $state->{module} - exit status $?");
my @committedfiles = ();
my %oldmeta;
@@ -1271,7 +1298,7 @@ sub req_ci
{
# fail everything if an up to date check fails
print "error 1 Up to date check failed for $filename\n";
chdir "/";
cleanupWorkTree();
exit;
}
@@ -1313,7 +1340,7 @@ sub req_ci
{
print "E No files to commit\n";
print "ok\n";
chdir "/";
cleanupWorkTree();
return;
}
@@ -1336,7 +1363,7 @@ sub req_ci
{
$log->warn("Commit failed (Invalid commit hash)");
print "error 1 Commit failed (unknown reason)\n";
chdir "/";
cleanupWorkTree();
exit;
}
@@ -1348,7 +1375,7 @@ sub req_ci
{
$log->warn("Commit failed (update hook declined to update ref)");
print "error 1 Commit failed (update hook declined)\n";
chdir "/";
cleanupWorkTree();
exit;
}
}
@@ -1358,6 +1385,7 @@ sub req_ci
"refs/heads/$state->{module}", $commithash, $parenthash)) {
$log->warn("update-ref for $state->{module} failed.");
print "error 1 Cannot commit -- update first\n";
cleanupWorkTree();
exit;
}
@@ -1409,12 +1437,12 @@ sub req_ci
}
print "Checked-in $dirpart\n";
print "$filename\n";
my $kopts = kopts_from_path($filepart);
my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
print "/$filepart/1.$meta->{revision}//$kopts/\n";
}
}
chdir "/";
cleanupWorkTree();
print "ok\n";
}
@@ -1757,15 +1785,9 @@ sub req_annotate
argsfromdir($updater);
# we'll need a temporary checkout dir
my $tmpdir = tempdir ( DIR => $TEMP_DIR );
my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
$log->info("Temp checkoutdir creation successful, basing annotate session work on '$tmpdir', index file is '$file_index'");
setupWorkTree();
$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
$ENV{GIT_WORK_TREE} = ".";
$ENV{GIT_INDEX_FILE} = $file_index;
chdir $tmpdir;
$log->info("Temp checkoutdir creation successful, basing annotate session work on '$work->{workDir}', index file is '$ENV{GIT_INDEX_FILE}'");
# foreach file specified on the command line ...
foreach my $filename ( @{$state->{args}} )
@@ -1789,10 +1811,10 @@ sub req_annotate
system("git-read-tree", $lastseenin);
unless ($? == 0)
{
print "E error running git-read-tree $lastseenin $file_index $!\n";
print "E error running git-read-tree $lastseenin $ENV{GIT_INDEX_FILE} $!\n";
return;
}
$log->info("Created index '$file_index' with commit $lastseenin - exit status $?");
$log->info("Created index '$ENV{GIT_INDEX_FILE}' with commit $lastseenin - exit status $?");
# do a checkout of the file
system('git-checkout-index', '-f', '-u', $filename);
@@ -1808,7 +1830,7 @@ sub req_annotate
# git-jsannotate telling us about commits we are hiding
# from the client.
my $a_hints = "$tmpdir/.annotate_hints";
my $a_hints = "$work->{workDir}/.annotate_hints";
if (!open(ANNOTATEHINTS, '>', $a_hints)) {
print "E failed to open '$a_hints' for writing: $!\n";
return;
@@ -1862,7 +1884,7 @@ sub req_annotate
}
# done; get out of the tempdir
chdir "/";
cleanupWorkDir();
print "ok\n";
@@ -2115,26 +2137,388 @@ sub filecleanup
return $filename;
}
sub validateGitDir
{
if( !defined($state->{CVSROOT}) )
{
print "error 1 CVSROOT not specified\n";
cleanupWorkTree();
exit;
}
if( $ENV{GIT_DIR} ne ($state->{CVSROOT} . '/') )
{
print "error 1 Internally inconsistent CVSROOT\n";
cleanupWorkTree();
exit;
}
}
# Setup working directory in a work tree with the requested version
# loaded in the index.
sub setupWorkTree
{
my ($ver) = @_;
validateGitDir();
if( ( defined($work->{state}) && $work->{state} != 1 ) ||
defined($work->{tmpDir}) )
{
$log->warn("Bad work tree state management");
print "error 1 Internal setup multiple work trees without cleanup\n";
cleanupWorkTree();
exit;
}
$work->{workDir} = tempdir ( DIR => $TEMP_DIR );
if( !defined($work->{index}) )
{
(undef, $work->{index}) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
}
chdir $work->{workDir} or
die "Unable to chdir to $work->{workDir}\n";
$log->info("Setting up GIT_WORK_TREE as '.' in '$work->{workDir}', index file is '$work->{index}'");
$ENV{GIT_WORK_TREE} = ".";
$ENV{GIT_INDEX_FILE} = $work->{index};
$work->{state} = 2;
if($ver)
{
system("git","read-tree",$ver);
unless ($? == 0)
{
$log->warn("Error running git-read-tree");
die "Error running git-read-tree $ver in $work->{workDir} $!\n";
}
}
# else # req_annotate reads tree for each file
}
# Ensure current directory is in some kind of working directory,
# with a recent version loaded in the index.
sub ensureWorkTree
{
if( defined($work->{tmpDir}) )
{
$log->warn("Bad work tree state management [ensureWorkTree()]");
print "error 1 Internal setup multiple dirs without cleanup\n";
cleanupWorkTree();
exit;
}
if( $work->{state} )
{
return;
}
validateGitDir();
if( !defined($work->{emptyDir}) )
{
$work->{emptyDir} = tempdir ( DIR => $TEMP_DIR, OPEN => 0);
}
chdir $work->{emptyDir} or
die "Unable to chdir to $work->{emptyDir}\n";
my $ver = `git show-ref -s refs/heads/$state->{module}`;
chomp $ver;
if ($ver !~ /^[0-9a-f]{40}$/)
{
$log->warn("Error from git show-ref -s refs/head$state->{module}");
print "error 1 cannot find the current HEAD of module";
cleanupWorkTree();
exit;
}
if( !defined($work->{index}) )
{
(undef, $work->{index}) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
}
$ENV{GIT_WORK_TREE} = ".";
$ENV{GIT_INDEX_FILE} = $work->{index};
$work->{state} = 1;
system("git","read-tree",$ver);
unless ($? == 0)
{
die "Error running git-read-tree $ver $!\n";
}
}
# Cleanup working directory that is not needed any longer.
sub cleanupWorkTree
{
if( ! $work->{state} )
{
return;
}
chdir "/" or die "Unable to chdir '/'\n";
if( defined($work->{workDir}) )
{
rmtree( $work->{workDir} );
undef $work->{workDir};
}
undef $work->{state};
}
# Setup a temporary directory (not a working tree), typically for
# merging dirty state as in req_update.
sub setupTmpDir
{
$work->{tmpDir} = tempdir ( DIR => $TEMP_DIR );
chdir $work->{tmpDir} or die "Unable to chdir $work->{tmpDir}\n";
return $work->{tmpDir};
}
# Clean up a previously setupTmpDir. Restore previous work tree if
# appropriate.
sub cleanupTmpDir
{
if ( !defined($work->{tmpDir}) )
{
$log->warn("cleanup tmpdir that has not been setup");
die "Cleanup tmpDir that has not been setup\n";
}
if( defined($work->{state}) )
{
if( $work->{state} == 1 )
{
chdir $work->{emptyDir} or
die "Unable to chdir to $work->{emptyDir}\n";
}
elsif( $work->{state} == 2 )
{
chdir $work->{workDir} or
die "Unable to chdir to $work->{emptyDir}\n";
}
else
{
$log->warn("Inconsistent work dir state");
die "Inconsistent work dir state\n";
}
}
else
{
chdir "/" or die "Unable to chdir '/'\n";
}
}
# Given a path, this function returns a string containing the kopts
# that should go into that path's Entries line. For example, a binary
# file should get -kb.
sub kopts_from_path
{
my ($path) = @_;
my ($path, $srcType, $name) = @_;
# Once it exists, the git attributes system should be used to look up
# what attributes apply to this path.
# Until then, take the setting from the config file
unless ( defined ( $cfg->{gitcvs}{allbinary} ) and $cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i )
if ( defined ( $cfg->{gitcvs}{usecrlfattr} ) and
$cfg->{gitcvs}{usecrlfattr} =~ /\s*(1|true|yes)\s*$/i )
{
# Return "" to give no special treatment to any path
return "";
} else {
# Alternatively, to have all files treated as if they are binary (which
# is more like git itself), always return the "-kb" option
return "-kb";
my ($val) = check_attr( "crlf", $path );
if ( $val eq "set" )
{
return "";
}
elsif ( $val eq "unset" )
{
return "-kb"
}
else
{
$log->info("Unrecognized check_attr crlf $path : $val");
}
}
if ( defined ( $cfg->{gitcvs}{allbinary} ) )
{
if( ($cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i) )
{
return "-kb";
}
elsif( ($cfg->{gitcvs}{allbinary} =~ /^\s*guess\s*$/i) )
{
if( $srcType eq "sha1Or-k" &&
!defined($name) )
{
my ($ret)=$state->{entries}{$path}{options};
if( !defined($ret) )
{
$ret=$state->{opt}{k};
if(defined($ret))
{
$ret="-k$ret";
}
else
{
$ret="";
}
}
if( ! ($ret=~/^(|-kb|-kkv|-kkvl|-kk|-ko|-kv)$/) )
{
print "E Bad -k option\n";
$log->warn("Bad -k option: $ret");
die "Error: Bad -k option: $ret\n";
}
return $ret;
}
else
{
if( is_binary($srcType,$name) )
{
$log->debug("... as binary");
return "-kb";
}
else
{
$log->debug("... as text");
}
}
}
}
# Return "" to give no special treatment to any path
return "";
}
sub check_attr
{
my ($attr,$path) = @_;
ensureWorkTree();
if ( open my $fh, '-|', "git", "check-attr", $attr, "--", $path )
{
my $val = <$fh>;
close $fh;
$val =~ s/.*: ([^:\r\n]*)\s*$/$1/;
return $val;
}
else
{
return undef;
}
}
# This should have the same heuristics as convert.c:is_binary() and related.
# Note that the bare CR test is done by callers in convert.c.
sub is_binary
{
my ($srcType,$name) = @_;
$log->debug("is_binary($srcType,$name)");
# Minimize amount of interpreted code run in the inner per-character
# loop for large files, by totalling each character value and
# then analyzing the totals.
my @counts;
my $i;
for($i=0;$i<256;$i++)
{
$counts[$i]=0;
}
my $fh = open_blob_or_die($srcType,$name);
my $line;
while( defined($line=<$fh>) )
{
# Any '\0' and bare CR are considered binary.
if( $line =~ /\0|(\r[^\n])/ )
{
close($fh);
return 1;
}
# Count up each character in the line:
my $len=length($line);
for($i=0;$i<$len;$i++)
{
$counts[ord(substr($line,$i,1))]++;
}
}
close $fh;
# Don't count CR and LF as either printable/nonprintable
$counts[ord("\n")]=0;
$counts[ord("\r")]=0;
# Categorize individual character count into printable and nonprintable:
my $printable=0;
my $nonprintable=0;
for($i=0;$i<256;$i++)
{
if( $i < 32 &&
$i != ord("\b") &&
$i != ord("\t") &&
$i != 033 && # ESC
$i != 014 ) # FF
{
$nonprintable+=$counts[$i];
}
elsif( $i==127 ) # DEL
{
$nonprintable+=$counts[$i];
}
else
{
$printable+=$counts[$i];
}
}
return ($printable >> 7) < $nonprintable;
}
# Returns open file handle. Possible invocations:
# - open_blob_or_die("file",$filename);
# - open_blob_or_die("sha1",$filehash);
sub open_blob_or_die
{
my ($srcType,$name) = @_;
my ($fh);
if( $srcType eq "file" )
{
if( !open $fh,"<",$name )
{
$log->warn("Unable to open file $name: $!");
die "Unable to open file $name: $!\n";
}
}
elsif( $srcType eq "sha1" || $srcType eq "sha1Or-k" )
{
unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{40}$/ )
{
$log->warn("Need filehash");
die "Need filehash\n";
}
my $type = `git cat-file -t $name`;
chomp $type;
unless ( defined ( $type ) and $type eq "blob" )
{
$log->warn("Invalid type '$type' for '$name'");
die ( "Invalid type '$type' (expected 'blob')" )
}
my $size = `git cat-file -s $name`;
chomp $size;
$log->debug("open_blob_or_die($name) size=$size, type=$type");
unless( open $fh, '-|', "git", "cat-file", "blob", $name )
{
$log->warn("Unable to open sha1 $name");
die "Unable to open sha1 $name\n";
}
}
else
{
$log->warn("Unknown type of blob source: $srcType");
die "Unknown type of blob source: $srcType\n";
}
return $fh;
}
# Generate a CVS author name from Git author information, by taking

View File

@@ -107,6 +107,11 @@ error_on_no_merge_candidates () {
}
test true = "$rebase" && {
git update-index --refresh &&
git diff-files --quiet &&
git diff-index --cached --quiet HEAD -- ||
die "refusing to pull with rebase: your working tree is not up-to-date"
. git-parse-remote &&
origin="$1"
test -z "$origin" && origin=$(get_default_remote)

View File

@@ -56,9 +56,9 @@ output () {
require_clean_work_tree () {
# test if working tree is dirty
git rev-parse --verify HEAD > /dev/null &&
git update-index --refresh &&
git diff-files --quiet &&
git diff-index --cached --quiet HEAD -- ||
git update-index --ignore-submodules --refresh &&
git diff-files --quiet --ignore-submodules &&
git diff-index --cached --quiet HEAD --ignore-submodules -- ||
die "Working tree is dirty"
}
@@ -377,11 +377,12 @@ do
# Sanity check
git rev-parse --verify HEAD >/dev/null ||
die "Cannot read HEAD"
git update-index --refresh && git diff-files --quiet ||
git update-index --ignore-submodules --refresh &&
git diff-files --quiet --ignore-submodules ||
die "Working tree is dirty"
# do we have anything to commit?
if git diff-index --cached --quiet HEAD --
if git diff-index --cached --quiet --ignore-submodules HEAD --
then
: Nothing to commit -- skip this
else

View File

@@ -60,7 +60,7 @@ continue_merge () {
fi
cmt=`cat "$dotest/current"`
if ! git diff-index --quiet HEAD --
if ! git diff-index --quiet --ignore-submodules HEAD --
then
if ! git commit --no-verify -C "$cmt"
then
@@ -150,7 +150,7 @@ while test $# != 0
do
case "$1" in
--continue)
git diff-files --quiet || {
git diff-files --quiet --ignore-submodules || {
echo "You must edit all merge conflicts and then"
echo "mark them as resolved using git add"
exit 1
@@ -282,8 +282,8 @@ else
fi
# The tree must be really really clean.
git update-index --refresh || exit
diff=$(git diff-index --cached --name-status -r HEAD --)
git update-index --ignore-submodules --refresh || exit
diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --)
case "$diff" in
?*) echo "cannot rebase: your index is not up-to-date"
echo "$diff"

View File

@@ -8,7 +8,7 @@ OPTIONS_SPEC="\
git-repack [options]
--
a pack everything in a single pack
A same as -a, and keep unreachable objects too
A same as -a, and turn unreachable objects loose
d remove redundant packs, and run git-prune-packed
f pass --no-reuse-delta to git-pack-objects
n do not run git-update-server-info
@@ -23,7 +23,7 @@ max-pack-size= maximum size of each packfile
SUBDIRECTORY_OK='Yes'
. git-sh-setup
no_update_info= all_into_one= remove_redundant= keep_unreachable=
no_update_info= all_into_one= remove_redundant= unpack_unreachable=
local= quiet= no_reuse= extra=
while test $# != 0
do
@@ -31,7 +31,7 @@ do
-n) no_update_info=t ;;
-a) all_into_one=t ;;
-A) all_into_one=t
keep_unreachable=--keep-unreachable ;;
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
-q) quiet=-q ;;
-f) no_reuse=--no-reuse-object ;;
@@ -79,9 +79,9 @@ case ",$all_into_one," in
if test -z "$args"
then
args='--unpacked --incremental'
elif test -n "$keep_unreachable"
elif test -n "$unpack_unreachable"
then
args="$args $keep_unreachable"
args="$args $unpack_unreachable"
fi
;;
esac

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