mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
27
Documentation/RelNotes-1.5.5.2.txt
Normal file
27
Documentation/RelNotes-1.5.5.2.txt
Normal 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.
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
---------------------------
|
||||
|
||||
@@ -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/".
|
||||
|
||||
|
||||
@@ -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
|
||||
------
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
------------
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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".
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -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
|
||||
|
||||
5
alias.c
5
alias.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
158
builtin-apply.c
158
builtin-apply.c
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
550
builtin-clone.c
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"))
|
||||
|
||||
22
builtin-gc.c
22
builtin-gc.c
@@ -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]);
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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
32
cache.h
@@ -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
|
||||
|
||||
4
color.c
4
color.c
@@ -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,
|
||||
|
||||
2
color.h
2
color.h
@@ -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);
|
||||
|
||||
27
config.c
27
config.c
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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)$,;
|
||||
|
||||
@@ -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;
|
||||
|
||||
4
daemon.c
4
daemon.c
@@ -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
17
diff.c
@@ -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
5
diff.h
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
104
git-bisect.sh
104
git-bisect.sh
@@ -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 () {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user