mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'mingw/master' into devel
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 gitcore-tutorial.txt gitglossary.txt
|
||||
|
||||
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
|
||||
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
|
||||
@@ -11,16 +12,11 @@ MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
|
||||
|
||||
DOC_HTML=$(MAN_HTML)
|
||||
|
||||
ARTICLES = tutorial
|
||||
ARTICLES += tutorial-2
|
||||
ARTICLES += core-tutorial
|
||||
ARTICLES += cvs-migration
|
||||
ARTICLES += diffcore
|
||||
ARTICLES = diffcore
|
||||
ARTICLES += howto-index
|
||||
ARTICLES += repository-layout
|
||||
ARTICLES += everyday
|
||||
ARTICLES += git-tools
|
||||
ARTICLES += glossary
|
||||
# with their own formatting rules.
|
||||
SP_ARTICLES = howto/revert-branch-rebase howto/using-merge-subtree user-manual
|
||||
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
|
||||
|
||||
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.
|
||||
12
Documentation/RelNotes-1.5.5.3.txt
Normal file
12
Documentation/RelNotes-1.5.5.3.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
GIT v1.5.5.3 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.5.2
|
||||
--------------------
|
||||
|
||||
* "git send-email --compose" did not notice that non-ascii contents
|
||||
needed some MIME magic.
|
||||
|
||||
* "git fast-export" did not export octopus merges correctly.
|
||||
|
||||
Also comes with various documentation updates.
|
||||
@@ -6,16 +6,30 @@ Updates since v1.5.5
|
||||
|
||||
(subsystems)
|
||||
|
||||
* Comes with updated gitk and git-gui.
|
||||
|
||||
(portability)
|
||||
|
||||
* git will build on AIX better than before now.
|
||||
|
||||
* core.ignorecase configuration variable can be used to work better on
|
||||
filesystems that are not case sensitive.
|
||||
|
||||
* "git init" now autodetects the case sensitivity of the filesystem and
|
||||
sets core.ignorecase accordingly.
|
||||
|
||||
(performance)
|
||||
|
||||
* "git clone" was rewritten in C. This will hopefully help cloning a
|
||||
repository with insane number of refs.
|
||||
|
||||
* "git rebase --onto $there $from $branch" used to switch to the tip of
|
||||
$branch only to immediately reset back to $from, smudging work tree
|
||||
files unnecessarily. This has been optimized.
|
||||
|
||||
* Object creation codepath in "git-svn" has been optimized by enhancing
|
||||
plumbing commands git-cat-file and git-hash-object.
|
||||
|
||||
(usability, bells and whistles)
|
||||
|
||||
* "git add -p" (and the "patch" subcommand of "git add -i") can choose to
|
||||
@@ -23,20 +37,57 @@ Updates since v1.5.5
|
||||
|
||||
* "git bisect help" gives longer and more helpful usage information.
|
||||
|
||||
* "git bisect" does not use a special branch "bisect" anymore; instead, it
|
||||
does its work on a detached HEAD.
|
||||
|
||||
* "git branch" (and "git checkout -b") can be told to set up
|
||||
branch.<name>.rebase automatically, so that later you can say "git pull"
|
||||
and magically cause "git pull --rebase" to happen.
|
||||
|
||||
* "git branch --merged" and "git branch --no-merged" can be used to list
|
||||
branches that have already been merged (or not yet merged) to the
|
||||
current branch.
|
||||
|
||||
* "git cherry-pick" and "git revert" can add a sign-off.
|
||||
|
||||
* "git commit" mentions the author identity when you are committing
|
||||
somebody else's changes.
|
||||
|
||||
* "git diff/log --dirstat" output is consistent between binary and textual
|
||||
changes.
|
||||
|
||||
* "git filter-branch" rewrites signed tags by demoting them to annotated.
|
||||
|
||||
* "git format-patch --no-binary" can produce a patch that lack binary
|
||||
changes (i.e. cannot be used to propagate the whole changes) meant only
|
||||
for reviewing.
|
||||
|
||||
* "git init --bare" is a synonym for "git --bare init" now.
|
||||
|
||||
* "git gc --auto" honors a new pre-aut-gc hook to temporarily disable it.
|
||||
|
||||
* "git log --pretty=tformat:<custom format>" gives a LF after each entry,
|
||||
instead of giving a LF between each pair of entries which is how
|
||||
"git log --pretty=format:<custom format>" works.
|
||||
|
||||
* "git log" and friends learned the "--graph" option to show the ancestry
|
||||
graph at the left margin of the output.
|
||||
|
||||
* "git log" and friends can be told to use date format that is different
|
||||
from the default via 'log.date' configuration variable.
|
||||
|
||||
* "git send-email" now can send out messages outside a git repository.
|
||||
|
||||
* "git send-email --compose" was made aware of rfc2047 quoting.
|
||||
|
||||
* "git status" can optionally include output from "git submodule
|
||||
summary".
|
||||
|
||||
* "git svn" learned --add-author-from option to propagate the authorship
|
||||
by munging the commit log message.
|
||||
|
||||
* new object creation and looking up in "git svn" has been optimized.
|
||||
|
||||
* "gitweb" can read from a system-wide configuration file.
|
||||
|
||||
(internal)
|
||||
@@ -54,6 +105,6 @@ this release, unless otherwise noted.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.5-56-g5f0734f
|
||||
O=v1.5.6-rc1
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -205,10 +205,13 @@ Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
|
||||
handling).
|
||||
|
||||
core.ignoreStat::
|
||||
The working copy files are assumed to stay unchanged until you
|
||||
mark them otherwise manually - Git will not detect the file changes
|
||||
by lstat() calls. This is useful on systems where those are very
|
||||
slow, such as Microsoft Windows. See linkgit:git-update-index[1].
|
||||
If true, commands which modify both the working tree and the index
|
||||
will mark the updated paths with the "assume unchanged" bit in the
|
||||
index. These marked files are then assumed to stay unchanged in the
|
||||
working copy, until you mark them otherwise manually - Git will not
|
||||
detect the file changes by lstat() calls. This is useful on systems
|
||||
where those are very slow, such as Microsoft Windows.
|
||||
See linkgit:git-update-index[1].
|
||||
False by default.
|
||||
|
||||
core.preferSymlinkRefs::
|
||||
@@ -523,8 +526,10 @@ color.status.<slot>::
|
||||
one of `header` (the header text of the status message),
|
||||
`added` or `updated` (files which are added but not committed),
|
||||
`changed` (files which are changed but not added in the index),
|
||||
or `untracked` (files which are not tracked by git). The values of
|
||||
these variables may be specified as in color.branch.<slot>.
|
||||
`untracked` (files which are not tracked by git), or
|
||||
`nobranch` (the color the 'no branch' warning is shown in, defaulting
|
||||
to red). The values of these variables may be specified as in
|
||||
color.branch.<slot>.
|
||||
|
||||
commit.template::
|
||||
Specify a file to use as the template for new commit messages.
|
||||
@@ -660,11 +665,24 @@ gitcvs.logfile::
|
||||
Path to a log file where the CVS server interface well... logs
|
||||
various stuff. See linkgit:git-cvsserver[1].
|
||||
|
||||
gitcvs.usecrlfattr
|
||||
If true, the server will look up the `crlf` attribute for
|
||||
files to determine the '-k' modes to use. If `crlf` is set,
|
||||
the '-k' mode will be left blank, so cvs clients will
|
||||
treat it as text. If `crlf` is explicitly unset, the file
|
||||
will be set with '-kb' mode, which supresses any newline munging
|
||||
the client might otherwise do. If `crlf` is not specified,
|
||||
then 'gitcvs.allbinary' is used. See linkgit:gitattribute[5].
|
||||
|
||||
gitcvs.allbinary::
|
||||
If true, all files are sent to the client in mode '-kb'. This
|
||||
causes the client to treat all files as binary files which suppresses
|
||||
any newline munging it otherwise might do. A work-around for the
|
||||
fact that there is no way yet to set single files to mode '-kb'.
|
||||
This is used if 'gitcvs.usecrlfattr' does not resolve
|
||||
the correct '-kb' mode to use. If true, all
|
||||
unresolved files are sent to the client in
|
||||
mode '-kb'. This causes the client to treat them
|
||||
as binary files, which suppresses any newline munging it
|
||||
otherwise might do. Alternatively, if it is set to "guess",
|
||||
then the contents of the file are examined to decide if
|
||||
it is binary, similar to 'core.autocrlf'.
|
||||
|
||||
gitcvs.dbname::
|
||||
Database used by git-cvsserver to cache revision information
|
||||
@@ -695,8 +713,9 @@ gitcvs.dbTableNamePrefix::
|
||||
linkgit:git-cvsserver[1] for details). Any non-alphabetic
|
||||
characters will be replaced with underscores.
|
||||
|
||||
All gitcvs variables except for 'gitcvs.allbinary' can also be
|
||||
specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'
|
||||
All gitcvs variables except for 'gitcvs.usecrlfattr' and
|
||||
'gitcvs.allbinary' can also be specified as
|
||||
'gitcvs.<access_method>.<varname>' (where 'access_method'
|
||||
is one of "ext" and "pserver") to make them apply only for the given
|
||||
access method.
|
||||
|
||||
@@ -815,6 +834,12 @@ instaweb.port::
|
||||
The port number to bind the gitweb httpd to. See
|
||||
linkgit:git-instaweb[1].
|
||||
|
||||
log.date::
|
||||
Set default date-time mode for the log command. Setting log.date
|
||||
value is similar to using git log's --date option. The value is one of
|
||||
following alternatives: {relative,local,default,iso,rfc,short}.
|
||||
See linkgit:git-log[1].
|
||||
|
||||
log.showroot::
|
||||
If true, the initial commit will be shown as a big creation event.
|
||||
This is equivalent to a diff against an empty tree.
|
||||
|
||||
@@ -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,7 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [-u] [--refresh]
|
||||
[--] <filepattern>...
|
||||
[--ignore-errors] [--] <filepattern>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -83,6 +83,11 @@ OPTIONS
|
||||
Don't add the file(s), but only refresh their stat()
|
||||
information in the index.
|
||||
|
||||
\--ignore-errors::
|
||||
If some files could not be added because of errors indexing
|
||||
them, do not abort the operation, but continue adding the
|
||||
others. The command shall still exit with non-zero status.
|
||||
|
||||
\--::
|
||||
This option can be used to separate command-line options from
|
||||
the list of files, (useful when filenames might be mistaken
|
||||
@@ -241,7 +246,7 @@ characters that need C-quoting. `core.quotepath` configuration can be
|
||||
used to work this limitation around to some degree, but backslash,
|
||||
double-quote and control characters will still have problems.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-status[1]
|
||||
linkgit:git-rm[1]
|
||||
|
||||
@@ -9,7 +9,7 @@ git-bundle - Move objects and refs by archive
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-bundle' create <file> [git-rev-list args]
|
||||
'git-bundle' create <file> <git-rev-list args>
|
||||
'git-bundle' verify <file>
|
||||
'git-bundle' list-heads <file> [refname...]
|
||||
'git-bundle' unbundle <file> [refname...]
|
||||
|
||||
@@ -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
|
||||
------
|
||||
|
||||
@@ -13,6 +13,8 @@ DESCRIPTION
|
||||
-----------
|
||||
The changeset (or "diff") of each commit between the fork-point and <head>
|
||||
is compared against each commit between the fork-point and <upstream>.
|
||||
The commits are compared with their 'patch id', obtained from linkgit:git-patch-id[1]
|
||||
program.
|
||||
|
||||
Every commit that doesn't exist in the <upstream> branch
|
||||
has its id (sha1) reported, prefixed by a symbol. The ones that have
|
||||
@@ -56,6 +58,10 @@ OPTIONS
|
||||
<limit>::
|
||||
Do not report commits up to (and including) limit.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-patch-id[1]
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
|
||||
@@ -88,7 +88,7 @@ Discussion
|
||||
|
||||
include::i18n.txt[]
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-write-tree[1]
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
|
||||
'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-W] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@@ -65,11 +65,22 @@ OPTIONS
|
||||
-w::
|
||||
Specify the location of the CVS checkout to use for the export. This
|
||||
option does not require GIT_DIR to be set before execution if the
|
||||
current directory is within a git repository.
|
||||
current directory is within a git repository. The default is the
|
||||
value of 'cvsexportcommit.cvsdir'.
|
||||
|
||||
-W::
|
||||
Tell cvsexportcommit that the current working directory is not only
|
||||
a Git checkout, but also the CVS checkout. Therefore, Git will
|
||||
reset the working directory to the parent commit before proceeding.
|
||||
|
||||
-v::
|
||||
Verbose.
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
cvsexportcommit.cvsdir::
|
||||
The default location of the CVS checkout to use for the export.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
||||
@@ -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
|
||||
------------
|
||||
|
||||
@@ -174,7 +174,7 @@ upload-pack::
|
||||
upload-archive::
|
||||
This serves `git-archive --remote`. It is disabled by
|
||||
default, but a repository can enable it by setting
|
||||
`daemon.uploadarchive` configuration item to `true`.
|
||||
`daemon.uploadarch` configuration item to `true`.
|
||||
|
||||
receive-pack::
|
||||
This serves `git-send-pack` clients, allowing anonymous
|
||||
@@ -257,7 +257,7 @@ selectively enable/disable services per repository::
|
||||
----------------------------------------------------------------
|
||||
[daemon]
|
||||
uploadpack = false
|
||||
uploadarchive = true
|
||||
uploadarch = true
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ git-diff-files - Compares files in the working tree and the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|--no-index] [<common diff options>] [<path>...]
|
||||
'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc] [<common diff options>] [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -36,9 +36,6 @@ omit diff output for unmerged entries and just show "Unmerged".
|
||||
diff, similar to the way 'diff-tree' shows a merge
|
||||
commit with these flags.
|
||||
|
||||
--no-index::
|
||||
Compare the two given files / directories.
|
||||
|
||||
-q::
|
||||
Remain silent even on nonexistent files
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ OPTIONS
|
||||
stdin. The commit id is expected on stdout.
|
||||
+
|
||||
As a special extension, the commit filter may emit multiple
|
||||
commit ids; in that case, ancestors of the original commit will
|
||||
commit ids; in that case, the rewritten children of the original commit will
|
||||
have all of them as parents.
|
||||
+
|
||||
You can use the 'map' convenience function in this filter, and other
|
||||
|
||||
@@ -223,7 +223,7 @@ as e-mailable patches:
|
||||
$ git format-patch -3
|
||||
------------
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-am[1], linkgit:git-send-email[1]
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ If you are expecting some objects to be collected and they aren't, check
|
||||
all of those locations and decide whether it makes sense in your case to
|
||||
remove those references.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-prune[1]
|
||||
linkgit:git-reflog[1]
|
||||
|
||||
@@ -79,9 +79,9 @@ git gui browser maint::
|
||||
selected in the browser can be viewed with the internal
|
||||
blame viewer.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
'gitk(1)'::
|
||||
linkgit:gitk[1]::
|
||||
The git repository browser. Shows branches, commit history
|
||||
and file differences. gitk is the utility started by
|
||||
git-gui's Repository Visualize actions.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-init' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
'git-init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
|
||||
|
||||
OPTIONS
|
||||
@@ -20,6 +20,11 @@ OPTIONS
|
||||
|
||||
Only print error and warning messages, all other output will be suppressed.
|
||||
|
||||
--bare::
|
||||
|
||||
Create a bare repository. If GIT_DIR environment is not set, it is set to the
|
||||
current working directory.
|
||||
|
||||
--template=<template_directory>::
|
||||
|
||||
Provide the directory from which templates will be used. The default template
|
||||
|
||||
@@ -177,7 +177,7 @@ top of the directory tree. A pattern read from a file specified
|
||||
by --exclude-per-directory is relative to the directory that the
|
||||
pattern file appears in.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-read-tree[1], linkgit:gitignore[5]
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ Documentation
|
||||
-------------
|
||||
Documentation by Junio C Hamano
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-rev-list[1]
|
||||
linkgit:git-repack[1]
|
||||
|
||||
@@ -46,7 +46,7 @@ Documentation
|
||||
--------------
|
||||
Documentation by Lukas Sandström <lukass@etek.chalmers.se>
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-pack-objects[1]
|
||||
linkgit:git-repack[1]
|
||||
|
||||
@@ -42,7 +42,7 @@ Documentation
|
||||
--------------
|
||||
Documentation by Ryan Anderson <ryan@michonline.com>
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-pack-objects[1]
|
||||
linkgit:git-repack[1]
|
||||
|
||||
@@ -66,7 +66,7 @@ many other housekeeping tasks.
|
||||
For a description of which objects are considered for pruning, see
|
||||
git-fsck's --unreachable option.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
linkgit:git-fsck[1],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -345,7 +345,7 @@ middle of doing, and when your working tree is ready (i.e. you
|
||||
have finished your work-in-progress), attempt the merge again.
|
||||
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
|
||||
linkgit:gitignore[5]
|
||||
|
||||
@@ -128,7 +128,7 @@ $ git merge origin
|
||||
------------
|
||||
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-fetch[1]
|
||||
linkgit:git-branch[1]
|
||||
|
||||
@@ -8,7 +8,7 @@ git-repack - Pack unpacked objects in a repository
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
|
||||
'git-repack' [-a] [-A] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -37,6 +37,18 @@ OPTIONS
|
||||
leaves behind, but `git fsck --full` shows as
|
||||
dangling.
|
||||
|
||||
-A::
|
||||
Same as `-a`, but any unreachable objects in a previous
|
||||
pack become loose, unpacked objects, instead of being
|
||||
left in the old pack. Unreachable objects are never
|
||||
intentionally added to a pack, even when repacking.
|
||||
When used with '-d', this option
|
||||
prevents unreachable objects from being immediately
|
||||
deleted by way of being left in the old pack and then
|
||||
removed. Instead, the loose unreachable objects
|
||||
will be pruned according to normal expiry rules
|
||||
with the next linkgit:git-gc[1].
|
||||
|
||||
-d::
|
||||
After packing, if the newly created packs make some
|
||||
existing packs redundant, remove the redundant packs.
|
||||
@@ -55,8 +67,11 @@ OPTIONS
|
||||
linkgit:git-pack-objects[1].
|
||||
|
||||
-n::
|
||||
Do not update the server information with
|
||||
`git update-server-info`.
|
||||
Do not update the server information with
|
||||
`git update-server-info`. This option skips
|
||||
updating local catalog files needed to publish
|
||||
this repository (or a direct copy of it)
|
||||
over HTTP or FTP. See gitlink:git-update-server-info[1].
|
||||
|
||||
--window=[N], --depth=[N]::
|
||||
These two options affect how the objects contained in the pack are
|
||||
@@ -107,7 +122,7 @@ Documentation
|
||||
--------------
|
||||
Documentation by Ryan Anderson <ryan@michonline.com>
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-pack-objects[1]
|
||||
linkgit:git-prune-packed[1]
|
||||
|
||||
@@ -243,16 +243,18 @@ Here is an illustration, by Jon Loeliger. Both commit nodes B
|
||||
and C are parents of commit node A. Parent commits are ordered
|
||||
left-to-right.
|
||||
|
||||
G H I J
|
||||
\ / \ /
|
||||
D E F
|
||||
\ | / \
|
||||
\ | / |
|
||||
\|/ |
|
||||
B C
|
||||
\ /
|
||||
\ /
|
||||
A
|
||||
........................................
|
||||
G H I J
|
||||
\ / \ /
|
||||
D E F
|
||||
\ | / \
|
||||
\ | / |
|
||||
\|/ |
|
||||
B C
|
||||
\ /
|
||||
\ /
|
||||
A
|
||||
........................................
|
||||
|
||||
A = = A^0
|
||||
B = A^ = A^1 = A~1
|
||||
@@ -378,6 +380,31 @@ C? option C with an optional argument"
|
||||
eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
|
||||
------------
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
* Print the object name of the current commit:
|
||||
+
|
||||
------------
|
||||
$ git rev-parse --verify HEAD
|
||||
------------
|
||||
|
||||
* Print the commit object name from the revision in the $REV shell variable:
|
||||
+
|
||||
------------
|
||||
$ git rev-parse --verify $REV
|
||||
------------
|
||||
+
|
||||
This will error out if $REV is empty or not a valid revision.
|
||||
|
||||
* Same as above:
|
||||
+
|
||||
------------
|
||||
$ git rev-parse --default master --verify $REV
|
||||
------------
|
||||
+
|
||||
but if $REV is empty, the commit object name from master will be printed.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -93,7 +93,7 @@ git-rm -f git-*.sh::
|
||||
(i.e. you are listing the files explicitly), it
|
||||
does not remove `subdir/git-foo.sh`.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-add[1]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -57,7 +57,7 @@ to -1 or an unlimited number), the submodule summary will be enabled and a
|
||||
summary of commits for modified submodules will be shown (see --summary-limit
|
||||
option of linkgit:git-submodule[1]).
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gitignore[5]
|
||||
|
||||
|
||||
@@ -61,6 +61,16 @@ COMMANDS
|
||||
Set the 'useSvnsyncProps' option in the [svn-remote] config.
|
||||
--rewrite-root=<URL>;;
|
||||
Set the 'rewriteRoot' option in the [svn-remote] config.
|
||||
--use-log-author;;
|
||||
When retrieving svn commits into git (as part of fetch, rebase, or
|
||||
dcommit operations), look for the first From: or Signed-off-by: line
|
||||
in the log message and use that as the author string.
|
||||
--add-author-from;;
|
||||
When committing to svn from git (as part of commit or dcommit
|
||||
operations), if the existing log message doesn't already have a
|
||||
From: or Signed-off-by: line, append a From: line based on the
|
||||
git commit's author string. If you use this, then --use-log-author
|
||||
will retrieve a valid author string for all commits.
|
||||
--username=<USER>;;
|
||||
For transports that SVN handles authentication for (http,
|
||||
https, and plain svn), specify the username. For other
|
||||
@@ -196,10 +206,10 @@ Any other arguments are passed directly to `git log'
|
||||
independently of git-svn functions.
|
||||
|
||||
'create-ignore'::
|
||||
|
||||
Recursively finds the svn:ignore property on directories and
|
||||
creates matching .gitignore files. The resulting files are staged to
|
||||
be committed, but are not committed.
|
||||
be committed, but are not committed. Use -r/--revision to refer to a
|
||||
specfic revision.
|
||||
|
||||
'show-ignore'::
|
||||
Recursively finds and lists the svn:ignore property on
|
||||
@@ -223,6 +233,19 @@ Any other arguments are passed directly to `git log'
|
||||
argument. Use the --url option to output only the value of the
|
||||
'URL:' field.
|
||||
|
||||
'proplist'::
|
||||
Lists the properties stored in the Subversion repository about a
|
||||
given file or directory. Use -r/--revision to refer to a specific
|
||||
Subversion revision.
|
||||
|
||||
'propget'::
|
||||
Gets the Subversion property given as the first argument, for a
|
||||
file. A specific revision can be specified with -r/--revision.
|
||||
|
||||
'show-externals'::
|
||||
Shows the Subversion externals. Use -r/--revision to specify a
|
||||
specific revision.
|
||||
|
||||
--
|
||||
|
||||
OPTIONS
|
||||
@@ -342,11 +365,15 @@ Passed directly to git-rebase when using 'dcommit' if a
|
||||
-n::
|
||||
--dry-run::
|
||||
|
||||
This is only used with the 'dcommit' command.
|
||||
This can be used with the 'dcommit' and 'rebase' commands.
|
||||
|
||||
Print out the series of git arguments that would show
|
||||
For 'dcommit', print out the series of git arguments that would show
|
||||
which diffs would be committed to SVN.
|
||||
|
||||
For 'rebase', display the local branch associated with the upstream svn
|
||||
repository associated with the current branch and the URL of svn
|
||||
repository that will be fetched from.
|
||||
|
||||
--
|
||||
|
||||
ADVANCED OPTIONS
|
||||
|
||||
@@ -15,6 +15,7 @@ SYNOPSIS
|
||||
[--cacheinfo <mode> <object> <file>]\*
|
||||
[--chmod=(+|-)x]
|
||||
[--assume-unchanged | --no-assume-unchanged]
|
||||
[--ignore-submodules]
|
||||
[--really-refresh] [--unresolve] [--again | -g]
|
||||
[--info-only] [--index-info]
|
||||
[-z] [--stdin]
|
||||
@@ -54,6 +55,10 @@ OPTIONS
|
||||
default behavior is to error out. This option makes
|
||||
git-update-index continue anyway.
|
||||
|
||||
--ignore-submodules:
|
||||
Do not try to update submodules. This option is only respected
|
||||
when passed before --refresh.
|
||||
|
||||
--unmerged::
|
||||
If --refresh finds unmerged changes in the index, the default
|
||||
behavior is to error out. This option makes git-update-index
|
||||
@@ -307,7 +312,7 @@ The command looks at `core.ignorestat` configuration variable. See
|
||||
'Using "assume unchanged" bit' section above.
|
||||
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-config[1],
|
||||
linkgit:git-add[1]
|
||||
|
||||
@@ -45,7 +45,7 @@ Your parents must have hated you!::
|
||||
Your sysadmin must hate you!::
|
||||
The password(5) name field is longer than a giant static buffer.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-commit-tree[1]
|
||||
linkgit:git-tag[1]
|
||||
|
||||
@@ -20,10 +20,10 @@ Git is a fast, scalable, distributed revision control system with an
|
||||
unusually rich command set that provides both high-level operations
|
||||
and full access to internals.
|
||||
|
||||
See this link:tutorial.html[tutorial] to get started, then see
|
||||
See this linkgit:gittutorial[7][tutorial] to get started, then see
|
||||
link:everyday.html[Everyday Git] for a useful minimum set of commands, and
|
||||
"man git-commandname" for documentation of each command. CVS users may
|
||||
also want to read link:cvs-migration.html[CVS migration]. See
|
||||
also want to read linkgit:gitcvs-migration[7][CVS migration]. See
|
||||
link:user-manual.html[Git User's Manual] for a more in-depth
|
||||
introduction.
|
||||
|
||||
@@ -46,10 +46,12 @@ Documentation for older releases are available here:
|
||||
* link:v1.5.5/git.html[documentation for release 1.5.5]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.5.5.3.txt[1.5.5.3],
|
||||
link:RelNotes-1.5.5.2.txt[1.5.5.2],
|
||||
link:RelNotes-1.5.5.1.txt[1.5.5.1],
|
||||
link:RelNotes-1.5.5.txt[1.5.5].
|
||||
|
||||
* link:v1.5.5.1/git.html[documentation for release 1.5.5.1]
|
||||
* link:v1.5.5.3/git.html[documentation for release 1.5.5.3]
|
||||
|
||||
* link:v1.5.4.5/git.html[documentation for release 1.5.4.5]
|
||||
|
||||
@@ -172,7 +174,7 @@ See the references above to get started using git. The following is
|
||||
probably more detail than necessary for a first-time user.
|
||||
|
||||
The link:user-manual.html#git-concepts[git concepts chapter of the
|
||||
user-manual] and the link:core-tutorial.html[Core tutorial] both provide
|
||||
user-manual] and the linkgit:gitcore-tutorial[7][Core tutorial] both provide
|
||||
introductions to the underlying git architecture.
|
||||
|
||||
See also the link:howto-index.html[howto] documents for some useful
|
||||
@@ -372,7 +374,7 @@ Higher level SCMs may provide and manage additional information in the
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
Please see the link:glossary.html[glossary] document.
|
||||
Please see the linkgit:gitglossary[7][glossary] document.
|
||||
|
||||
|
||||
Environment Variables
|
||||
@@ -516,7 +518,7 @@ Discussion[[Discussion]]
|
||||
|
||||
More detail on the following is available from the
|
||||
link:user-manual.html#git-concepts[git concepts chapter of the
|
||||
user-manual] and the link:core-tutorial.html[Core tutorial].
|
||||
user-manual] and the linkgit:gitcore-tutorial[7][Core tutorial].
|
||||
|
||||
A git project normally consists of a working directory with a ".git"
|
||||
subdirectory at the top level. The .git directory contains, among other
|
||||
@@ -577,6 +579,13 @@ The documentation for git suite was started by David Greaves
|
||||
<david@dgreaves.com>, and later enhanced greatly by the
|
||||
contributors on the git-list <git@vger.kernel.org>.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
|
||||
linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
|
||||
linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
A git core tutorial for developers
|
||||
==================================
|
||||
gitcore-tutorial(7)
|
||||
===================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
NAME
|
||||
----
|
||||
gitcore-tutorial - A git core tutorial for developers
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
git *
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This tutorial explains how to use the "core" git programs to set up and
|
||||
work with a git repository.
|
||||
|
||||
If you just need to use git as a revision control system you may prefer
|
||||
to start with link:tutorial.html[a tutorial introduction to git] or
|
||||
to start with linkgit:gittutorial[7][a tutorial introduction to git] or
|
||||
link:user-manual.html[the git user manual].
|
||||
|
||||
However, an understanding of these low-level tools can be helpful if
|
||||
@@ -1581,7 +1589,7 @@ suggested in the previous section may be new to you. You do not
|
||||
have to worry. git supports "shared public repository" style of
|
||||
cooperation you are probably more familiar with as well.
|
||||
|
||||
See link:cvs-migration.html[git for CVS users] for the details.
|
||||
See linkgit:gitcvs-migration[7][git for CVS users] for the details.
|
||||
|
||||
Bundling your work together
|
||||
---------------------------
|
||||
@@ -1679,3 +1687,13 @@ merge two at a time, documenting how you resolved the conflicts,
|
||||
and the reason why you preferred changes made in one side over
|
||||
the other. Otherwise it would make the project history harder
|
||||
to follow, not easier.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
|
||||
linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite.
|
||||
@@ -1,5 +1,16 @@
|
||||
git for CVS users
|
||||
=================
|
||||
gitcvs-migration(7)
|
||||
===================
|
||||
|
||||
NAME
|
||||
----
|
||||
gitcvs-migration - git for CVS users
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
git cvsimport *
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Git differs from CVS in that every working tree contains a repository with
|
||||
a full copy of the project history, and no repository is inherently more
|
||||
@@ -8,8 +19,8 @@ designating a single shared repository which people can synchronize with;
|
||||
this document explains how to do that.
|
||||
|
||||
Some basic familiarity with git is required. This
|
||||
link:tutorial.html[tutorial introduction to git] and the
|
||||
link:glossary.html[git glossary] should be sufficient.
|
||||
linkgit:gittutorial[7][tutorial introduction to git] and the
|
||||
linkgit:gitglossary[7][git glossary] should be sufficient.
|
||||
|
||||
Developing against a shared repository
|
||||
--------------------------------------
|
||||
@@ -71,7 +82,7 @@ Setting Up a Shared Repository
|
||||
|
||||
We assume you have already created a git repository for your project,
|
||||
possibly created from scratch or from a tarball (see the
|
||||
link:tutorial.html[tutorial]), or imported from an already existing CVS
|
||||
linkgit:gittutorial[7][tutorial]), or imported from an already existing CVS
|
||||
repository (see the next section).
|
||||
|
||||
Assume your existing repo is at /home/alice/myproject. Create a new "bare"
|
||||
@@ -170,3 +181,16 @@ variants of this model.
|
||||
|
||||
With a small group, developers may just pull changes from each other's
|
||||
repositories without the need for a central maintainer.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7],
|
||||
linkgit:gittutorial-2[7],
|
||||
linkgit:gitcore-tutorial[7],
|
||||
linkgit:gitglossary[7],
|
||||
link:everyday.html[Everyday Git],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite.
|
||||
25
Documentation/gitglossary.txt
Normal file
25
Documentation/gitglossary.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
gitglossary(7)
|
||||
==============
|
||||
|
||||
NAME
|
||||
----
|
||||
gitglossary - A GIT Glossary
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
include::glossary-content.txt[]
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
|
||||
linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite.
|
||||
@@ -85,7 +85,7 @@ Files
|
||||
Gitk creates the .gitk file in your $HOME directory to store preferences
|
||||
such as display options, font, and colors.
|
||||
|
||||
See Also
|
||||
SEE ALSO
|
||||
--------
|
||||
'qgit(1)'::
|
||||
A repository browser written in C++ using Qt.
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
A tutorial introduction to git: part two
|
||||
========================================
|
||||
gittutorial-2(7)
|
||||
================
|
||||
|
||||
You should work through link:tutorial.html[A tutorial introduction to
|
||||
NAME
|
||||
----
|
||||
gittutorial-2 - A tutorial introduction to git: part two
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
git *
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
You should work through linkgit:gittutorial[7][A tutorial introduction to
|
||||
git] before reading this tutorial.
|
||||
|
||||
The goal of this tutorial is to introduce two fundamental pieces of
|
||||
@@ -379,7 +390,7 @@ in the index file is identical to the one in the working directory.
|
||||
In addition to being the staging area for new commits, the index file
|
||||
is also populated from the object database when checking out a
|
||||
branch, and is used to hold the trees involved in a merge operation.
|
||||
See the link:core-tutorial.html[core tutorial] and the relevant man
|
||||
See the linkgit:gitcore-tutorial[7][core tutorial] and the relevant man
|
||||
pages for details.
|
||||
|
||||
What next?
|
||||
@@ -389,18 +400,31 @@ At this point you should know everything necessary to read the man
|
||||
pages for any of the git commands; one good place to start would be
|
||||
with the commands mentioned in link:everyday.html[Everyday git]. You
|
||||
should be able to find any unknown jargon in the
|
||||
link:glossary.html[Glossary].
|
||||
linkgit:gitglossary[7][Glossary].
|
||||
|
||||
The link:user-manual.html[Git User's Manual] provides a more
|
||||
comprehensive introduction to git.
|
||||
|
||||
The link:cvs-migration.html[CVS migration] document explains how to
|
||||
The linkgit:gitcvs-migration[7][CVS migration] document explains how to
|
||||
import a CVS repository into git, and shows how to use git in a
|
||||
CVS-like way.
|
||||
|
||||
For some interesting examples of git use, see the
|
||||
link:howto-index.html[howtos].
|
||||
|
||||
For git developers, the link:core-tutorial.html[Core tutorial] goes
|
||||
For git developers, the linkgit:gitcore-tutorial[7][Core tutorial] goes
|
||||
into detail on the lower-level git mechanisms involved in, for
|
||||
example, creating a new commit.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7],
|
||||
linkgit:gitcvs-migration[7],
|
||||
linkgit:gitcore-tutorial[7],
|
||||
linkgit:gitglossary[7],
|
||||
link:everyday.html[Everyday git],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite.
|
||||
@@ -1,5 +1,16 @@
|
||||
A tutorial introduction to git (for version 1.5.1 or newer)
|
||||
===========================================================
|
||||
gittutorial(7)
|
||||
==============
|
||||
|
||||
NAME
|
||||
----
|
||||
gittutorial - A tutorial introduction to git (for version 1.5.1 or newer)
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
git *
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This tutorial explains how to import a new project into git, make
|
||||
changes to it, and share changes with other developers.
|
||||
@@ -381,7 +392,7 @@ see linkgit:git-pull[1] for details.
|
||||
|
||||
Git can also be used in a CVS-like mode, with a central repository
|
||||
that various users push changes to; see linkgit:git-push[1] and
|
||||
link:cvs-migration.html[git for CVS users].
|
||||
linkgit:gitcvs-migration[7][git for CVS users].
|
||||
|
||||
Exploring history
|
||||
-----------------
|
||||
@@ -560,7 +571,7 @@ is based:
|
||||
used to create commits, check out working directories, and
|
||||
hold the various trees involved in a merge.
|
||||
|
||||
link:tutorial-2.html[Part two of this tutorial] explains the object
|
||||
linkgit:gittutorial-2[7][Part two of this tutorial] explains the object
|
||||
database, the index file, and a few other odds and ends that you'll
|
||||
need to make the most of git.
|
||||
|
||||
@@ -581,4 +592,17 @@ digressions that may be interesting at this point are:
|
||||
|
||||
* link:everyday.html[Everyday GIT with 20 Commands Or So]
|
||||
|
||||
* link:cvs-migration.html[git for CVS users].
|
||||
* linkgit:gitcvs-migration[7][git for CVS users].
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial-2[7],
|
||||
linkgit:gitcvs-migration[7],
|
||||
linkgit:gitcore-tutorial[7],
|
||||
linkgit:gitglossary[7],
|
||||
link:everyday.html[Everyday git],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite.
|
||||
@@ -1,6 +1,3 @@
|
||||
GIT Glossary
|
||||
============
|
||||
|
||||
[[def_alternate_object_database]]alternate object database::
|
||||
Via the alternates mechanism, a <<def_repository,repository>>
|
||||
can inherit part of its <<def_object_database,object database>>
|
||||
@@ -90,11 +87,10 @@ to point at the new commit.
|
||||
source code management tools.
|
||||
|
||||
[[def_DAG]]DAG::
|
||||
Directed acyclic graph. The <<def_commit,commit>> objects form a
|
||||
Directed acyclic graph. The <<def_commit_object,commit objects>> form a
|
||||
directed acyclic graph, because they have parents (directed), and the
|
||||
graph of commit objects is acyclic (there is no
|
||||
<<def_chain,chain>> which begins and ends with the same
|
||||
<<def_object,object>>).
|
||||
graph of commit objects is acyclic (there is no <<def_chain,chain>>
|
||||
which begins and ends with the same <<def_object,object>>).
|
||||
|
||||
[[def_dangling_object]]dangling object::
|
||||
An <<def_unreachable_object,unreachable object>> which is not
|
||||
@@ -250,9 +246,10 @@ This commit is referred to as a "merge commit", or sometimes just a
|
||||
the <<def_hash,hash>> of the object.
|
||||
|
||||
[[def_object_type]]object type::
|
||||
One of the identifiers
|
||||
"<<def_commit,commit>>","<<def_tree,tree>>","<<def_tag,tag>>" or "<<def_blob_object,blob>>"
|
||||
describing the type of an <<def_object,object>>.
|
||||
One of the identifiers "<<def_commit_object,commit>>",
|
||||
"<<def_tree_object,tree>>", "<<def_tag_object,tag>>" or
|
||||
"<<def_blob_object,blob>>" describing the type of an
|
||||
<<def_object,object>>.
|
||||
|
||||
[[def_octopus]]octopus::
|
||||
To <<def_merge,merge>> more than two <<def_branch,branches>>. Also denotes an
|
||||
@@ -1,6 +1,8 @@
|
||||
<repository>::
|
||||
The "remote" repository that is the source of a fetch
|
||||
or pull operation. See the section <<URLS,GIT URLS>> below.
|
||||
or pull operation. This parameter can be either a URL
|
||||
(see the section <<URLS,GIT URLS>> below) or the name
|
||||
of a remote (see the section <<REMOTES,REMOTES>> below).
|
||||
|
||||
<refspec>::
|
||||
The canonical format of a <refspec> parameter is
|
||||
|
||||
@@ -13,10 +13,11 @@ include::pretty-options.txt[]
|
||||
|
||||
Synonym for `--date=relative`.
|
||||
|
||||
--date={relative,local,default,iso,rfc}::
|
||||
--date={relative,local,default,iso,rfc,short}::
|
||||
|
||||
Only takes effect for dates shown in human-readable format, such
|
||||
as when using "--pretty".
|
||||
as when using "--pretty". `log.date` config variable sets a default
|
||||
value for log command's --date option.
|
||||
+
|
||||
`--date=relative` shows dates relative to the current time,
|
||||
e.g. "2 hours ago".
|
||||
@@ -75,6 +76,16 @@ you would get an output line this:
|
||||
-xxxxxxx... 1st on a
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
--graph::
|
||||
|
||||
Draw a text-based graphical representation of the commit history
|
||||
on the left hand side of the output. This may cause extra lines
|
||||
to be printed in between commits, in order for the graph history
|
||||
to be drawn properly.
|
||||
+
|
||||
This implies the '--topo-order' option by default, but the
|
||||
'--date-order' option may also be specified.
|
||||
|
||||
Diff Formatting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
179
Documentation/technical/api-history-graph.txt
Normal file
179
Documentation/technical/api-history-graph.txt
Normal file
@@ -0,0 +1,179 @@
|
||||
history graph API
|
||||
=================
|
||||
|
||||
The graph API is used to draw a text-based representation of the commit
|
||||
history. The API generates the graph in a line-by-line fashion.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
Core functions:
|
||||
|
||||
* `graph_init()` creates a new `struct git_graph`
|
||||
|
||||
* `graph_release()` destroys a `struct git_graph`, and frees the memory
|
||||
associated with it.
|
||||
|
||||
* `graph_update()` moves the graph to a new commit.
|
||||
|
||||
* `graph_next_line()` outputs the next line of the graph into a strbuf. It
|
||||
does not add a terminating newline.
|
||||
|
||||
* `graph_padding_line()` outputs a line of vertical padding in the graph. It
|
||||
is similar to `graph_next_line()`, but is guaranteed to never print the line
|
||||
containing the current commit. Where `graph_next_line()` would print the
|
||||
commit line next, `graph_padding_line()` prints a line that simply extends
|
||||
all branch lines downwards one row, leaving their positions unchanged.
|
||||
|
||||
* `graph_is_commit_finished()` determines if the graph has output all lines
|
||||
necessary for the current commit. If `graph_update()` is called before all
|
||||
lines for the current commit have been printed, the next call to
|
||||
`graph_next_line()` will output an ellipsis, to indicate that a portion of
|
||||
the graph was omitted.
|
||||
|
||||
The following utility functions are wrappers around `graph_next_line()` and
|
||||
`graph_is_commit_finished()`. They always print the output to stdout.
|
||||
They can all be called with a NULL graph argument, in which case no graph
|
||||
output will be printed.
|
||||
|
||||
* `graph_show_commit()` calls `graph_next_line()` until it returns non-zero.
|
||||
This prints all graph lines up to, and including, the line containing this
|
||||
commit. Output is printed to stdout. The last line printed does not contain
|
||||
a terminating newline. This should not be called if the commit line has
|
||||
already been printed, or it will loop forever.
|
||||
|
||||
* `graph_show_oneline()` calls `graph_next_line()` and prints the result to
|
||||
stdout. The line printed does not contain a terminating newline.
|
||||
|
||||
* `graph_show_padding()` calls `graph_padding_line()` and prints the result to
|
||||
stdout. The line printed does not contain a terminating newline.
|
||||
|
||||
* `graph_show_remainder()` calls `graph_next_line()` until
|
||||
`graph_is_commit_finished()` returns non-zero. Output is printed to stdout.
|
||||
The last line printed does not contain a terminating newline. Returns 1 if
|
||||
output was printed, and 0 if no output was necessary.
|
||||
|
||||
* `graph_show_strbuf()` prints the specified strbuf to stdout, prefixing all
|
||||
lines but the first with a graph line. The caller is responsible for
|
||||
ensuring graph output for the first line has already been printed to stdout.
|
||||
(This can be done with `graph_show_commit()` or `graph_show_oneline()`.) If
|
||||
a NULL graph is supplied, the strbuf is printed as-is.
|
||||
|
||||
* `graph_show_commit_msg()` is similar to `graph_show_strbuf()`, but it also
|
||||
prints the remainder of the graph, if more lines are needed after the strbuf
|
||||
ends. It is better than directly calling `graph_show_strbuf()` followed by
|
||||
`graph_show_remainder()` since it properly handles buffers that do not end in
|
||||
a terminating newline. The output printed by `graph_show_commit_msg()` will
|
||||
end in a newline if and only if the strbuf ends in a newline.
|
||||
|
||||
Data structure
|
||||
--------------
|
||||
`struct git_graph` is an opaque data type used to store the current graph
|
||||
state.
|
||||
|
||||
Calling sequence
|
||||
----------------
|
||||
|
||||
* Create a `struct git_graph` by calling `graph_init()`. When using the
|
||||
revision walking API, this is done automatically by `setup_revisions()` if
|
||||
the '--graph' option is supplied.
|
||||
|
||||
* Use the revision walking API to walk through a group of contiguous commits.
|
||||
The `get_revision()` function automatically calls `graph_update()` each time
|
||||
it is invoked.
|
||||
|
||||
* For each commit, call `graph_next_line()` repeatedly, until
|
||||
`graph_is_commit_finished()` returns non-zero. Each call go
|
||||
`graph_next_line()` will output a single line of the graph. The resulting
|
||||
lines will not contain any newlines. `graph_next_line()` returns 1 if the
|
||||
resulting line contains the current commit, or 0 if this is merely a line
|
||||
needed to adjust the graph before or after the current commit. This return
|
||||
value can be used to determine where to print the commit summary information
|
||||
alongside the graph output.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
* `graph_update()` must be called with commits in topological order. It should
|
||||
not be called on a commit if it has already been invoked with an ancestor of
|
||||
that commit, or the graph output will be incorrect.
|
||||
|
||||
* `graph_update()` must be called on a contiguous group of commits. If
|
||||
`graph_update()` is called on a particular commit, it should later be called
|
||||
on all parents of that commit. Parents must not be skipped, or the graph
|
||||
output will appear incorrect.
|
||||
+
|
||||
`graph_update()` may be used on a pruned set of commits only if the parent list
|
||||
has been rewritten so as to include only ancestors from the pruned set.
|
||||
|
||||
* The graph API does not currently support reverse commit ordering. In
|
||||
order to implement reverse ordering, the graphing API needs an
|
||||
(efficient) mechanism to find the children of a commit.
|
||||
|
||||
Sample usage
|
||||
------------
|
||||
|
||||
------------
|
||||
struct commit *commit;
|
||||
struct git_graph *graph = graph_init(opts);
|
||||
|
||||
while ((commit = get_revision(opts)) != NULL) {
|
||||
graph_update(graph, commit);
|
||||
while (!graph_is_commit_finished(graph))
|
||||
{
|
||||
struct strbuf sb;
|
||||
int is_commit_line;
|
||||
|
||||
strbuf_init(&sb, 0);
|
||||
is_commit_line = graph_next_line(graph, &sb);
|
||||
fputs(sb.buf, stdout);
|
||||
|
||||
if (is_commit_line)
|
||||
log_tree_commit(opts, commit);
|
||||
else
|
||||
putchar(opts->diffopt.line_termination);
|
||||
}
|
||||
}
|
||||
|
||||
graph_release(graph);
|
||||
------------
|
||||
|
||||
Sample output
|
||||
-------------
|
||||
|
||||
The following is an example of the output from the graph API. This output does
|
||||
not include any commit summary information--callers are responsible for
|
||||
outputting that information, if desired.
|
||||
|
||||
------------
|
||||
*
|
||||
*
|
||||
M
|
||||
|\
|
||||
* |
|
||||
| | *
|
||||
| \ \
|
||||
| \ \
|
||||
M-. \ \
|
||||
|\ \ \ \
|
||||
| | * | |
|
||||
| | | | | *
|
||||
| | | | | *
|
||||
| | | | | M
|
||||
| | | | | |\
|
||||
| | | | | | *
|
||||
| * | | | | |
|
||||
| | | | | M \
|
||||
| | | | | |\ |
|
||||
| | | | * | | |
|
||||
| | | | * | | |
|
||||
* | | | | | | |
|
||||
| |/ / / / / /
|
||||
|/| / / / / /
|
||||
* | | | | | |
|
||||
|/ / / / / /
|
||||
* | | | | |
|
||||
| | | | | *
|
||||
| | | | |/
|
||||
| | | | *
|
||||
------------
|
||||
@@ -1,9 +1,67 @@
|
||||
revision walking API
|
||||
====================
|
||||
|
||||
The revision walking API offers functions to build a list of revisions
|
||||
and then iterate over that list.
|
||||
|
||||
Calling sequence
|
||||
----------------
|
||||
|
||||
The walking API has a given calling sequence: first you need to
|
||||
initialize a rev_info structure, then add revisions to control what kind
|
||||
of revision list do you want to get, finally you can iterate over the
|
||||
revision list.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
`init_revisions`::
|
||||
|
||||
Initialize a rev_info structure with default values. The second
|
||||
parameter may be NULL or can be prefix path, and then the `.prefix`
|
||||
variable will be set to it. This is typically the first function you
|
||||
want to call when you want to deal with a revision list. After calling
|
||||
this function, you are free to customize options, like set
|
||||
`.ignore_merges` to 0 if you don't want to ignore merges, and so on. See
|
||||
`revision.h` for a complete list of available options.
|
||||
|
||||
`add_pending_object`::
|
||||
|
||||
This function can be used if you want to add commit objects as revision
|
||||
information. You can use the `UNINTERESTING` object flag to indicate if
|
||||
you want to include or exclude the given commit (and commits reachable
|
||||
from the given commit) from the revision list.
|
||||
+
|
||||
NOTE: If you have the commits as a string list then you probably want to
|
||||
use setup_revisions(), instead of parsing each string and using this
|
||||
function.
|
||||
|
||||
`setup_revisions`::
|
||||
|
||||
Parse revision information, filling in the `rev_info` structure, and
|
||||
removing the used arguments from the argument list. Returns the number
|
||||
of arguments left that weren't recognized, which are also moved to the
|
||||
head of the argument list. The last parameter is used in case no
|
||||
parameter given by the first two arguments.
|
||||
|
||||
`prepare_revision_walk`::
|
||||
|
||||
Prepares the rev_info structure for a walk. You should check if it
|
||||
returns any error (non-zero return code) and if it does not, you can
|
||||
start using get_revision() to do the iteration.
|
||||
|
||||
`get_revision`::
|
||||
|
||||
Takes a pointer to a `rev_info` structure and iterates over it,
|
||||
returning a `struct commit *` each time you call it. The end of the
|
||||
revision list is indicated by returning a NULL pointer.
|
||||
|
||||
Data structures
|
||||
---------------
|
||||
|
||||
Talk about <revision.h>, things like:
|
||||
|
||||
* two diff_options, one for path limiting, another for output;
|
||||
* calling sequence: init_revisions(), setup_revsions(), get_revision();
|
||||
* remaining functions;
|
||||
|
||||
(Linus, JC, Dscho)
|
||||
|
||||
@@ -1,11 +1,46 @@
|
||||
include::urls.txt[]
|
||||
|
||||
REMOTES
|
||||
-------
|
||||
REMOTES[[REMOTES]]
|
||||
------------------
|
||||
|
||||
In addition to the above, as a short-hand, the name of a
|
||||
file in `$GIT_DIR/remotes` directory can be given; the
|
||||
named file should be in the following format:
|
||||
The name of one of the following can be used instead
|
||||
of a URL as `<repository>` argument:
|
||||
|
||||
* a remote in the git configuration file: `$GIT_DIR/config`,
|
||||
* a file in the `$GIT_DIR/remotes` directory, or
|
||||
* a file in the `$GIT_DIR/branches` directory.
|
||||
|
||||
All of these also allow you to omit the refspec from the command line
|
||||
because they each contain a refspec which git will use by default.
|
||||
|
||||
Named remote in configuration file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can choose to provide the name of a remote which you had previously
|
||||
configured using linkgit:git-remote[1], linkgit:git-config[1]
|
||||
or even by a manual edit to the `$GIT_DIR/config` file. The URL of
|
||||
this remote will be used to access the repository. The refspec
|
||||
of this remote will be used by default when you do
|
||||
not provide a refspec on the command line. The entry in the
|
||||
config file would appear like this:
|
||||
|
||||
------------
|
||||
[remote "<name>"]
|
||||
url = <url>
|
||||
push = <refspec>
|
||||
fetch = <refspec>
|
||||
------------
|
||||
|
||||
|
||||
Named file in `$GIT_DIR/remotes`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can choose to provide the name of a
|
||||
file in `$GIT_DIR/remotes`. The URL
|
||||
in this file will be used to access the repository. The refspec
|
||||
in this file will be used as default when you do not
|
||||
provide a refspec on the command line. This file should have the
|
||||
following format:
|
||||
|
||||
------------
|
||||
URL: one of the above URL format
|
||||
@@ -14,42 +49,34 @@ named file should be in the following format:
|
||||
|
||||
------------
|
||||
|
||||
Then such a short-hand is specified in place of
|
||||
<repository> without <refspec> parameters on the command
|
||||
line, <refspec> specified on `Push:` lines or `Pull:`
|
||||
lines are used for `git-push` and `git-fetch`/`git-pull`,
|
||||
respectively. Multiple `Push:` and `Pull:` lines may
|
||||
`Push:` lines are used by `git-push` and
|
||||
`Pull:` lines are used by `git-pull` and `git-fetch`.
|
||||
Multiple `Push:` and `Pull:` lines may
|
||||
be specified for additional branch mappings.
|
||||
|
||||
Or, equivalently, in the `$GIT_DIR/config` (note the use
|
||||
of `fetch` instead of `Pull:`):
|
||||
Named file in `$GIT_DIR/branches`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can choose to provide the name of a
|
||||
file in `$GIT_DIR/branches`.
|
||||
The URL in this file will be used to access the repository.
|
||||
This file should have the following format:
|
||||
|
||||
|
||||
------------
|
||||
[remote "<remote>"]
|
||||
url = <url>
|
||||
push = <refspec>
|
||||
fetch = <refspec>
|
||||
|
||||
<url>#<head>
|
||||
------------
|
||||
|
||||
The name of a file in `$GIT_DIR/branches` directory can be
|
||||
specified as an older notation short-hand; the named
|
||||
file should contain a single line, a URL in one of the
|
||||
above formats, optionally followed by a hash `#` and the
|
||||
name of remote head (URL fragment notation).
|
||||
`$GIT_DIR/branches/<remote>` file that stores a <url>
|
||||
without the fragment is equivalent to have this in the
|
||||
corresponding file in the `$GIT_DIR/remotes/` directory.
|
||||
`<url>` is required; `#<head>` is optional.
|
||||
When you do not provide a refspec on the command line,
|
||||
git will use the following refspec, where `<head>` defaults to `master`,
|
||||
and `<repository>` is the name of this file
|
||||
you provided in the command line.
|
||||
|
||||
------------
|
||||
URL: <url>
|
||||
Pull: refs/heads/master:<remote>
|
||||
|
||||
refs/heads/<head>:<repository>
|
||||
------------
|
||||
|
||||
while having `<url>#<head>` is equivalent to
|
||||
|
||||
------------
|
||||
URL: <url>
|
||||
Pull: refs/heads/<head>:<remote>
|
||||
------------
|
||||
|
||||
|
||||
|
||||
@@ -1993,7 +1993,7 @@ the right to push to the same repository. In that case, the correct
|
||||
solution is to retry the push after first updating your work by either a
|
||||
pull or a fetch followed by a rebase; see the
|
||||
<<setting-up-a-shared-repository,next section>> and
|
||||
link:cvs-migration.html[git for CVS users] for more.
|
||||
linkgit:gitcvs-migration[7][git for CVS users] for more.
|
||||
|
||||
[[setting-up-a-shared-repository]]
|
||||
Setting up a shared repository
|
||||
@@ -2002,7 +2002,7 @@ Setting up a shared repository
|
||||
Another way to collaborate is by using a model similar to that
|
||||
commonly used in CVS, where several developers with special rights
|
||||
all push to and pull from a single shared repository. See
|
||||
link:cvs-migration.html[git for CVS users] for instructions on how to
|
||||
linkgit:gitcvs-migration[7][git for CVS users] for instructions on how to
|
||||
set this up.
|
||||
|
||||
However, while there is nothing wrong with git's support for shared
|
||||
@@ -4252,7 +4252,10 @@ You see, Git is actually the best tool to find out about the source of Git
|
||||
itself!
|
||||
|
||||
[[glossary]]
|
||||
include::glossary.txt[]
|
||||
GIT Glossary
|
||||
============
|
||||
|
||||
include::glossary-content.txt[]
|
||||
|
||||
[[git-quick-start]]
|
||||
Appendix A: Git Quick Reference
|
||||
|
||||
8
Makefile
8
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
|
||||
@@ -345,6 +344,7 @@ LIB_H += diff.h
|
||||
LIB_H += dir.h
|
||||
LIB_H += fsck.h
|
||||
LIB_H += git-compat-util.h
|
||||
LIB_H += graph.h
|
||||
LIB_H += grep.h
|
||||
LIB_H += hash.h
|
||||
LIB_H += list-objects.h
|
||||
@@ -374,6 +374,7 @@ LIB_H += tree.h
|
||||
LIB_H += tree-walk.h
|
||||
LIB_H += unpack-trees.h
|
||||
LIB_H += utf8.h
|
||||
LIB_H += wt-status.h
|
||||
|
||||
LIB_OBJS += alias.o
|
||||
LIB_OBJS += alloc.o
|
||||
@@ -403,6 +404,7 @@ LIB_OBJS += diffcore-order.o
|
||||
LIB_OBJS += diffcore-pickaxe.o
|
||||
LIB_OBJS += diffcore-rename.o
|
||||
LIB_OBJS += diff-delta.o
|
||||
LIB_OBJS += diff-no-index.o
|
||||
LIB_OBJS += diff-lib.o
|
||||
LIB_OBJS += diff.o
|
||||
LIB_OBJS += dir.o
|
||||
@@ -410,6 +412,7 @@ LIB_OBJS += entry.o
|
||||
LIB_OBJS += environment.o
|
||||
LIB_OBJS += exec_cmd.o
|
||||
LIB_OBJS += fsck.o
|
||||
LIB_OBJS += graph.o
|
||||
LIB_OBJS += grep.o
|
||||
LIB_OBJS += hash.o
|
||||
LIB_OBJS += help.o
|
||||
@@ -481,6 +484,7 @@ BUILTIN_OBJS += builtin-check-ref-format.o
|
||||
BUILTIN_OBJS += builtin-checkout-index.o
|
||||
BUILTIN_OBJS += builtin-checkout.o
|
||||
BUILTIN_OBJS += builtin-clean.o
|
||||
BUILTIN_OBJS += builtin-clone.o
|
||||
BUILTIN_OBJS += builtin-commit-tree.o
|
||||
BUILTIN_OBJS += builtin-commit.o
|
||||
BUILTIN_OBJS += builtin-config.o
|
||||
@@ -1261,7 +1265,7 @@ remove-dashes:
|
||||
ifeq ($(firstword $(subst /, ,$(template_dir))),..)
|
||||
template_instdir = $(gitexecdir)/$(template_dir)
|
||||
else
|
||||
template_instdir = $template_dir
|
||||
template_instdir = $(template_dir)
|
||||
endif
|
||||
export template_instdir
|
||||
|
||||
|
||||
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;
|
||||
|
||||
@@ -79,12 +79,18 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
|
||||
prune_directory(dir, pathspec, baselen);
|
||||
}
|
||||
|
||||
struct update_callback_data
|
||||
{
|
||||
int flags;
|
||||
int add_errors;
|
||||
};
|
||||
|
||||
static void update_callback(struct diff_queue_struct *q,
|
||||
struct diff_options *opt, void *cbdata)
|
||||
{
|
||||
int i, verbose;
|
||||
int i;
|
||||
struct update_callback_data *data = cbdata;
|
||||
|
||||
verbose = *((int *)cbdata);
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
struct diff_filepair *p = q->queue[i];
|
||||
const char *path = p->one->path;
|
||||
@@ -94,27 +100,36 @@ static void update_callback(struct diff_queue_struct *q,
|
||||
case DIFF_STATUS_UNMERGED:
|
||||
case DIFF_STATUS_MODIFIED:
|
||||
case DIFF_STATUS_TYPE_CHANGED:
|
||||
add_file_to_cache(path, verbose);
|
||||
if (add_file_to_cache(path, data->flags)) {
|
||||
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
|
||||
die("updating files failed");
|
||||
data->add_errors++;
|
||||
}
|
||||
break;
|
||||
case DIFF_STATUS_DELETED:
|
||||
remove_file_from_cache(path);
|
||||
if (verbose)
|
||||
if (!(data->flags & ADD_CACHE_PRETEND))
|
||||
remove_file_from_cache(path);
|
||||
if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
|
||||
printf("remove '%s'\n", path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_files_to_cache(int verbose, const char *prefix, const char **pathspec)
|
||||
int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
|
||||
{
|
||||
struct update_callback_data data;
|
||||
struct rev_info rev;
|
||||
init_revisions(&rev, prefix);
|
||||
setup_revisions(0, NULL, &rev, NULL);
|
||||
rev.prune_data = pathspec;
|
||||
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = update_callback;
|
||||
rev.diffopt.format_callback_data = &verbose;
|
||||
data.flags = flags;
|
||||
data.add_errors = 0;
|
||||
rev.diffopt.format_callback_data = &data;
|
||||
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
|
||||
return !!data.add_errors;
|
||||
}
|
||||
|
||||
static void refresh(int verbose, const char **pathspec)
|
||||
@@ -177,6 +192,7 @@ static const char ignore_error[] =
|
||||
"The following paths are ignored by one of your .gitignore files:\n";
|
||||
|
||||
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
||||
static int ignore_add_errors;
|
||||
|
||||
static struct option builtin_add_options[] = {
|
||||
OPT__DRY_RUN(&show_only),
|
||||
@@ -187,14 +203,26 @@ static struct option builtin_add_options[] = {
|
||||
OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
|
||||
OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
|
||||
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
||||
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
static int add_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcasecmp(var, "add.ignore-errors")) {
|
||||
ignore_add_errors = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int exit_status = 0;
|
||||
int i, newfd;
|
||||
const char **pathspec;
|
||||
struct dir_struct dir;
|
||||
int flags;
|
||||
|
||||
argc = parse_options(argc, argv, builtin_add_options,
|
||||
builtin_add_usage, 0);
|
||||
@@ -203,16 +231,20 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
if (add_interactive)
|
||||
exit(interactive_add(argc, argv, prefix));
|
||||
|
||||
git_config(git_default_config);
|
||||
git_config(add_config, NULL);
|
||||
|
||||
newfd = hold_locked_index(&lock_file, 1);
|
||||
|
||||
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
|
||||
(show_only ? ADD_CACHE_PRETEND : 0) |
|
||||
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0));
|
||||
|
||||
if (take_worktree_changes) {
|
||||
const char **pathspec;
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
add_files_to_cache(verbose, prefix, pathspec);
|
||||
exit_status = add_files_to_cache(prefix, pathspec, flags);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@@ -230,17 +262,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
|
||||
fill_directory(&dir, pathspec, ignored_too);
|
||||
|
||||
if (show_only) {
|
||||
const char *sep = "", *eof = "";
|
||||
for (i = 0; i < dir.nr; i++) {
|
||||
printf("%s%s", sep, dir.entries[i]->name);
|
||||
sep = " ";
|
||||
eof = "\n";
|
||||
}
|
||||
fputs(eof, stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
@@ -254,7 +275,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
for (i = 0; i < dir.nr; i++)
|
||||
add_file_to_cache(dir.entries[i]->name, verbose);
|
||||
if (add_file_to_cache(dir.entries[i]->name, flags)) {
|
||||
if (!ignore_add_errors)
|
||||
die("adding files failed");
|
||||
exit_status = 1;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (active_cache_changed) {
|
||||
@@ -263,5 +288,5 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
unsigned char rev[20];
|
||||
int flag;
|
||||
struct commit *head;
|
||||
int errs = 0;
|
||||
|
||||
int newfd;
|
||||
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||
@@ -106,13 +107,14 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
if (report_path_error(ps_matched, pathspec, 0))
|
||||
return 1;
|
||||
|
||||
/* Now we are committed to check them out */
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.force = 1;
|
||||
state.refresh_cache = 1;
|
||||
for (pos = 0; pos < active_nr; pos++) {
|
||||
struct cache_entry *ce = active_cache[pos];
|
||||
if (pathspec_match(pathspec, NULL, ce->name, 0)) {
|
||||
checkout_entry(ce, &state, NULL);
|
||||
errs |= checkout_entry(ce, &state, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +125,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
resolve_ref("HEAD", rev, 0, &flag);
|
||||
head = lookup_commit_reference_gently(rev, 1);
|
||||
|
||||
return post_checkout_hook(head, head, 0);
|
||||
errs |= post_checkout_hook(head, head, 0);
|
||||
return errs;
|
||||
}
|
||||
|
||||
static void show_local_changes(struct object *head)
|
||||
@@ -148,57 +151,50 @@ static void describe_detached_head(char *msg, struct commit *commit)
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
static int reset_to_new(struct tree *tree, int quiet)
|
||||
{
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc tree_desc;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.head_idx = -1;
|
||||
opts.update = 1;
|
||||
opts.reset = 1;
|
||||
opts.merge = 1;
|
||||
opts.fn = oneway_merge;
|
||||
opts.verbose_update = !quiet;
|
||||
opts.src_index = &the_index;
|
||||
opts.dst_index = &the_index;
|
||||
parse_tree(tree);
|
||||
init_tree_desc(&tree_desc, tree->buffer, tree->size);
|
||||
if (unpack_trees(1, &tree_desc, &opts))
|
||||
return 128;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reset_clean_to_new(struct tree *tree, int quiet)
|
||||
{
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc tree_desc;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.head_idx = -1;
|
||||
opts.skip_unmerged = 1;
|
||||
opts.reset = 1;
|
||||
opts.merge = 1;
|
||||
opts.fn = oneway_merge;
|
||||
opts.verbose_update = !quiet;
|
||||
opts.src_index = &the_index;
|
||||
opts.dst_index = &the_index;
|
||||
parse_tree(tree);
|
||||
init_tree_desc(&tree_desc, tree->buffer, tree->size);
|
||||
if (unpack_trees(1, &tree_desc, &opts))
|
||||
exit(128);
|
||||
}
|
||||
|
||||
struct checkout_opts {
|
||||
int quiet;
|
||||
int merge;
|
||||
int force;
|
||||
int writeout_error;
|
||||
|
||||
char *new_branch;
|
||||
int new_branch_log;
|
||||
enum branch_track track;
|
||||
};
|
||||
|
||||
static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
|
||||
{
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc tree_desc;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.head_idx = -1;
|
||||
opts.update = worktree;
|
||||
opts.skip_unmerged = !worktree;
|
||||
opts.reset = 1;
|
||||
opts.merge = 1;
|
||||
opts.fn = oneway_merge;
|
||||
opts.verbose_update = !o->quiet;
|
||||
opts.src_index = &the_index;
|
||||
opts.dst_index = &the_index;
|
||||
parse_tree(tree);
|
||||
init_tree_desc(&tree_desc, tree->buffer, tree->size);
|
||||
switch (unpack_trees(1, &tree_desc, &opts)) {
|
||||
case -2:
|
||||
o->writeout_error = 1;
|
||||
/*
|
||||
* We return 0 nevertheless, as the index is all right
|
||||
* and more importantly we have made best efforts to
|
||||
* update paths in the work tree, and we cannot revert
|
||||
* them.
|
||||
*/
|
||||
case 0:
|
||||
return 0;
|
||||
default:
|
||||
return 128;
|
||||
}
|
||||
}
|
||||
|
||||
struct branch_info {
|
||||
const char *name; /* The short name used */
|
||||
const char *path; /* The full name of a real branch */
|
||||
@@ -223,7 +219,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
read_cache();
|
||||
|
||||
if (opts->force) {
|
||||
ret = reset_to_new(new->commit->tree, opts->quiet);
|
||||
ret = reset_tree(new->commit->tree, opts, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
@@ -236,6 +232,8 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
topts.src_index = &the_index;
|
||||
topts.dst_index = &the_index;
|
||||
|
||||
topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
|
||||
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
|
||||
if (unmerged_cache()) {
|
||||
@@ -257,7 +255,8 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
tree = parse_tree_indirect(new->commit->object.sha1);
|
||||
init_tree_desc(&trees[1], tree->buffer, tree->size);
|
||||
|
||||
if (unpack_trees(2, trees, &topts)) {
|
||||
ret = unpack_trees(2, trees, &topts);
|
||||
if (ret == -1) {
|
||||
/*
|
||||
* Unpack couldn't do a trivial merge; either
|
||||
* give up or do a real merge, depending on
|
||||
@@ -282,15 +281,17 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
* entries in the index.
|
||||
*/
|
||||
|
||||
add_files_to_cache(0, NULL, NULL);
|
||||
add_files_to_cache(NULL, NULL, 0);
|
||||
work = write_tree_from_memory();
|
||||
|
||||
ret = reset_to_new(new->commit->tree, opts->quiet);
|
||||
ret = reset_tree(new->commit->tree, opts, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
merge_trees(new->commit->tree, work, old->commit->tree,
|
||||
new->name, "local", &result);
|
||||
reset_clean_to_new(new->commit->tree, opts->quiet);
|
||||
ret = reset_tree(new->commit->tree, opts, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,7 +491,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||
|
||||
update_refs_for_switch(opts, &old, new);
|
||||
|
||||
return post_checkout_hook(old.commit, new->commit, 1);
|
||||
ret = post_checkout_hook(old.commit, new->commit, 1);
|
||||
return ret || opts->writeout_error;
|
||||
}
|
||||
|
||||
int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
@@ -514,7 +516,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
memset(&new, 0, sizeof(new));
|
||||
|
||||
git_config(git_default_config);
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
opts.track = git_branch_track;
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ static const char *const builtin_clean_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int git_clean_config(const char *var, const char *value)
|
||||
static int git_clean_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "clean.requireforce"))
|
||||
force = !git_config_bool(var, value);
|
||||
return git_default_config(var, value);
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
@@ -50,7 +50,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
git_config(git_clean_config);
|
||||
git_config(git_clean_config, NULL);
|
||||
if (force < 0)
|
||||
force = 0;
|
||||
else
|
||||
|
||||
553
builtin-clone.c
Normal file
553
builtin-clone.c
Normal file
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Builtin "git clone"
|
||||
*
|
||||
* Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,
|
||||
* 2008 Daniel Barkalow <barkalow@iabervon.org>
|
||||
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
|
||||
*
|
||||
* Clone a repository into a different directory that does not yet exist.
|
||||
*/
|
||||
|
||||
#include "cache.h"
|
||||
#include "parse-options.h"
|
||||
#include "fetch-pack.h"
|
||||
#include "refs.h"
|
||||
#include "tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "unpack-trees.h"
|
||||
#include "transport.h"
|
||||
#include "strbuf.h"
|
||||
#include "dir.h"
|
||||
|
||||
/*
|
||||
* Overall FIXMEs:
|
||||
* - respect DB_ENVIRONMENT for .git/objects.
|
||||
*
|
||||
* Implementation notes:
|
||||
* - dropping use-separate-remote and no-separate-remote compatibility
|
||||
*
|
||||
*/
|
||||
static const char * const builtin_clone_usage[] = {
|
||||
"git-clone [options] [--] <repo> [<dir>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int option_quiet, option_no_checkout, option_bare;
|
||||
static int option_local, option_no_hardlinks, option_shared;
|
||||
static char *option_template, *option_reference, *option_depth;
|
||||
static char *option_origin = NULL;
|
||||
static char *option_upload_pack = "git-upload-pack";
|
||||
|
||||
static struct option builtin_clone_options[] = {
|
||||
OPT__QUIET(&option_quiet),
|
||||
OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
|
||||
"don't create a checkout"),
|
||||
OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
|
||||
OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
|
||||
OPT_BOOLEAN('l', "local", &option_local,
|
||||
"to clone from a local repository"),
|
||||
OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
|
||||
"don't use local hardlinks, always copy"),
|
||||
OPT_BOOLEAN('s', "shared", &option_shared,
|
||||
"setup as shared repository"),
|
||||
OPT_STRING(0, "template", &option_template, "path",
|
||||
"path the template repository"),
|
||||
OPT_STRING(0, "reference", &option_reference, "repo",
|
||||
"reference repository"),
|
||||
OPT_STRING('o', "origin", &option_origin, "branch",
|
||||
"use <branch> instead or 'origin' to track upstream"),
|
||||
OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
|
||||
"path to git-upload-pack on the remote"),
|
||||
OPT_STRING(0, "depth", &option_depth, "depth",
|
||||
"create a shallow clone of that depth"),
|
||||
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static char *get_repo_path(const char *repo, int *is_bundle)
|
||||
{
|
||||
static char *suffix[] = { "/.git", ".git", "" };
|
||||
static char *bundle_suffix[] = { ".bundle", "" };
|
||||
struct stat st;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
|
||||
const char *path;
|
||||
path = mkpath("%s%s", repo, suffix[i]);
|
||||
if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
|
||||
*is_bundle = 0;
|
||||
return xstrdup(make_absolute_path(path));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
|
||||
const char *path;
|
||||
path = mkpath("%s%s", repo, bundle_suffix[i]);
|
||||
if (!stat(path, &st) && S_ISREG(st.st_mode)) {
|
||||
*is_bundle = 1;
|
||||
return xstrdup(make_absolute_path(path));
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *guess_dir_name(const char *repo, int is_bundle)
|
||||
{
|
||||
const char *p, *start, *end, *limit;
|
||||
int after_slash_or_colon;
|
||||
|
||||
/* Guess dir name from repository: strip trailing '/',
|
||||
* strip trailing '[:/]*.{git,bundle}', strip leading '.*[/:]'. */
|
||||
|
||||
after_slash_or_colon = 1;
|
||||
limit = repo + strlen(repo);
|
||||
start = repo;
|
||||
end = limit;
|
||||
for (p = repo; p < limit; p++) {
|
||||
const char *prefix = is_bundle ? ".bundle" : ".git";
|
||||
if (!prefixcmp(p, prefix)) {
|
||||
if (!after_slash_or_colon)
|
||||
end = p;
|
||||
p += strlen(prefix) - 1;
|
||||
} else if (!prefixcmp(p, ".bundle")) {
|
||||
if (!after_slash_or_colon)
|
||||
end = p;
|
||||
p += 7;
|
||||
} else if (*p == '/' || *p == ':') {
|
||||
if (end == limit)
|
||||
end = p;
|
||||
after_slash_or_colon = 1;
|
||||
} else if (after_slash_or_colon) {
|
||||
start = p;
|
||||
end = limit;
|
||||
after_slash_or_colon = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return xstrndup(start, end - start);
|
||||
}
|
||||
|
||||
static int is_directory(const char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
return !stat(path, &buf) && S_ISDIR(buf.st_mode);
|
||||
}
|
||||
|
||||
static void setup_reference(const char *repo)
|
||||
{
|
||||
const char *ref_git;
|
||||
char *ref_git_copy;
|
||||
|
||||
struct remote *remote;
|
||||
struct transport *transport;
|
||||
const struct ref *extra;
|
||||
|
||||
ref_git = make_absolute_path(option_reference);
|
||||
|
||||
if (is_directory(mkpath("%s/.git/objects", ref_git)))
|
||||
ref_git = mkpath("%s/.git", ref_git);
|
||||
else if (!is_directory(mkpath("%s/objects", ref_git)))
|
||||
die("reference repository '%s' is not a local directory.",
|
||||
option_reference);
|
||||
|
||||
ref_git_copy = xstrdup(ref_git);
|
||||
|
||||
add_to_alternates_file(ref_git_copy);
|
||||
|
||||
remote = remote_get(ref_git_copy);
|
||||
transport = transport_get(remote, ref_git_copy);
|
||||
for (extra = transport_get_remote_refs(transport); extra;
|
||||
extra = extra->next)
|
||||
add_extra_ref(extra->name, extra->old_sha1, 0);
|
||||
|
||||
transport_disconnect(transport);
|
||||
|
||||
free(ref_git_copy);
|
||||
}
|
||||
|
||||
static void copy_or_link_directory(char *src, char *dest)
|
||||
{
|
||||
struct dirent *de;
|
||||
struct stat buf;
|
||||
int src_len, dest_len;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(src);
|
||||
if (!dir)
|
||||
die("failed to open %s\n", src);
|
||||
|
||||
if (mkdir(dest, 0777)) {
|
||||
if (errno != EEXIST)
|
||||
die("failed to create directory %s\n", dest);
|
||||
else if (stat(dest, &buf))
|
||||
die("failed to stat %s\n", dest);
|
||||
else if (!S_ISDIR(buf.st_mode))
|
||||
die("%s exists and is not a directory\n", dest);
|
||||
}
|
||||
|
||||
src_len = strlen(src);
|
||||
src[src_len] = '/';
|
||||
dest_len = strlen(dest);
|
||||
dest[dest_len] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
strcpy(src + src_len + 1, de->d_name);
|
||||
strcpy(dest + dest_len + 1, de->d_name);
|
||||
if (stat(src, &buf)) {
|
||||
warning ("failed to stat %s\n", src);
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
if (de->d_name[0] != '.')
|
||||
copy_or_link_directory(src, dest);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unlink(dest) && errno != ENOENT)
|
||||
die("failed to unlink %s\n", dest);
|
||||
if (!option_no_hardlinks) {
|
||||
if (!link(src, dest))
|
||||
continue;
|
||||
if (option_local)
|
||||
die("failed to create link %s\n", dest);
|
||||
option_no_hardlinks = 1;
|
||||
}
|
||||
if (copy_file(dest, src, 0666))
|
||||
die("failed to copy file to %s\n", dest);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static const struct ref *clone_local(const char *src_repo,
|
||||
const char *dest_repo)
|
||||
{
|
||||
const struct ref *ret;
|
||||
char src[PATH_MAX];
|
||||
char dest[PATH_MAX];
|
||||
struct remote *remote;
|
||||
struct transport *transport;
|
||||
|
||||
if (option_shared)
|
||||
add_to_alternates_file(src_repo);
|
||||
else {
|
||||
snprintf(src, PATH_MAX, "%s/objects", src_repo);
|
||||
snprintf(dest, PATH_MAX, "%s/objects", dest_repo);
|
||||
copy_or_link_directory(src, dest);
|
||||
}
|
||||
|
||||
remote = remote_get(src_repo);
|
||||
transport = transport_get(remote, src_repo);
|
||||
ret = transport_get_remote_refs(transport);
|
||||
transport_disconnect(transport);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *junk_work_tree;
|
||||
static const char *junk_git_dir;
|
||||
pid_t junk_pid;
|
||||
|
||||
static void remove_junk(void)
|
||||
{
|
||||
struct strbuf sb;
|
||||
if (getpid() != junk_pid)
|
||||
return;
|
||||
strbuf_init(&sb, 0);
|
||||
if (junk_git_dir) {
|
||||
strbuf_addstr(&sb, junk_git_dir);
|
||||
remove_dir_recursively(&sb, 0);
|
||||
strbuf_reset(&sb);
|
||||
}
|
||||
if (junk_work_tree) {
|
||||
strbuf_addstr(&sb, junk_work_tree);
|
||||
remove_dir_recursively(&sb, 0);
|
||||
strbuf_reset(&sb);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_junk_on_signal(int signo)
|
||||
{
|
||||
remove_junk();
|
||||
signal(SIGINT, SIG_DFL);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
static const struct ref *locate_head(const struct ref *refs,
|
||||
const struct ref *mapped_refs,
|
||||
const struct ref **remote_head_p)
|
||||
{
|
||||
const struct ref *remote_head = NULL;
|
||||
const struct ref *remote_master = NULL;
|
||||
const struct ref *r;
|
||||
for (r = refs; r; r = r->next)
|
||||
if (!strcmp(r->name, "HEAD"))
|
||||
remote_head = r;
|
||||
|
||||
for (r = mapped_refs; r; r = r->next)
|
||||
if (!strcmp(r->name, "refs/heads/master"))
|
||||
remote_master = r;
|
||||
|
||||
if (remote_head_p)
|
||||
*remote_head_p = remote_head;
|
||||
|
||||
/* If there's no HEAD value at all, never mind. */
|
||||
if (!remote_head)
|
||||
return NULL;
|
||||
|
||||
/* If refs/heads/master could be right, it is. */
|
||||
if (remote_master && !hashcmp(remote_master->old_sha1,
|
||||
remote_head->old_sha1))
|
||||
return remote_master;
|
||||
|
||||
/* Look for another ref that points there */
|
||||
for (r = mapped_refs; r; r = r->next)
|
||||
if (r != remote_head &&
|
||||
!hashcmp(r->old_sha1, remote_head->old_sha1))
|
||||
return r;
|
||||
|
||||
/* Nothing is the same */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ref *write_remote_refs(const struct ref *refs,
|
||||
struct refspec *refspec, const char *reflog)
|
||||
{
|
||||
struct ref *local_refs = NULL;
|
||||
struct ref **tail = &local_refs;
|
||||
struct ref *r;
|
||||
|
||||
get_fetch_map(refs, refspec, &tail, 0);
|
||||
get_fetch_map(refs, tag_refspec, &tail, 0);
|
||||
|
||||
for (r = local_refs; r; r = r->next)
|
||||
update_ref(reflog,
|
||||
r->peer_ref->name, r->old_sha1, NULL, 0, DIE_ON_ERR);
|
||||
return local_refs;
|
||||
}
|
||||
|
||||
int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int use_local_hardlinks = 1;
|
||||
int use_separate_remote = 1;
|
||||
int is_bundle = 0;
|
||||
struct stat buf;
|
||||
const char *repo_name, *repo, *work_tree, *git_dir;
|
||||
char *path, *dir;
|
||||
const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
|
||||
char branch_top[256], key[256], value[256];
|
||||
struct strbuf reflog_msg;
|
||||
|
||||
struct refspec refspec;
|
||||
|
||||
junk_pid = getpid();
|
||||
|
||||
argc = parse_options(argc, argv, builtin_clone_options,
|
||||
builtin_clone_usage, 0);
|
||||
|
||||
if (argc == 0)
|
||||
die("You must specify a repository to clone.");
|
||||
|
||||
if (option_no_hardlinks)
|
||||
use_local_hardlinks = 0;
|
||||
|
||||
if (option_bare) {
|
||||
if (option_origin)
|
||||
die("--bare and --origin %s options are incompatible.",
|
||||
option_origin);
|
||||
option_no_checkout = 1;
|
||||
use_separate_remote = 0;
|
||||
}
|
||||
|
||||
if (!option_origin)
|
||||
option_origin = "origin";
|
||||
|
||||
repo_name = argv[0];
|
||||
|
||||
path = get_repo_path(repo_name, &is_bundle);
|
||||
if (path)
|
||||
repo = path;
|
||||
else if (!strchr(repo_name, ':'))
|
||||
repo = xstrdup(make_absolute_path(repo_name));
|
||||
else
|
||||
repo = repo_name;
|
||||
|
||||
if (argc == 2)
|
||||
dir = xstrdup(argv[1]);
|
||||
else
|
||||
dir = guess_dir_name(repo_name, is_bundle);
|
||||
|
||||
if (!stat(dir, &buf))
|
||||
die("destination directory '%s' already exists.", dir);
|
||||
|
||||
strbuf_init(&reflog_msg, 0);
|
||||
strbuf_addf(&reflog_msg, "clone: from %s", repo);
|
||||
|
||||
if (option_bare)
|
||||
work_tree = NULL;
|
||||
else {
|
||||
work_tree = getenv("GIT_WORK_TREE");
|
||||
if (work_tree && !stat(work_tree, &buf))
|
||||
die("working tree '%s' already exists.", work_tree);
|
||||
}
|
||||
|
||||
if (option_bare || work_tree)
|
||||
git_dir = xstrdup(dir);
|
||||
else {
|
||||
work_tree = dir;
|
||||
git_dir = xstrdup(mkpath("%s/.git", dir));
|
||||
}
|
||||
|
||||
if (!option_bare) {
|
||||
junk_work_tree = work_tree;
|
||||
if (mkdir(work_tree, 0755))
|
||||
die("could not create work tree dir '%s'.", work_tree);
|
||||
set_git_work_tree(work_tree);
|
||||
}
|
||||
junk_git_dir = git_dir;
|
||||
atexit(remove_junk);
|
||||
signal(SIGINT, remove_junk_on_signal);
|
||||
|
||||
setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
|
||||
|
||||
set_git_dir(make_absolute_path(git_dir));
|
||||
|
||||
fprintf(stderr, "Initialize %s\n", git_dir);
|
||||
init_db(option_template, option_quiet ? INIT_DB_QUIET : 0);
|
||||
|
||||
if (option_reference)
|
||||
setup_reference(git_dir);
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
if (option_bare) {
|
||||
strcpy(branch_top, "refs/heads/");
|
||||
|
||||
git_config_set("core.bare", "true");
|
||||
} else {
|
||||
snprintf(branch_top, sizeof(branch_top),
|
||||
"refs/remotes/%s/", option_origin);
|
||||
|
||||
/* Configure the remote */
|
||||
snprintf(key, sizeof(key), "remote.%s.url", option_origin);
|
||||
git_config_set(key, repo);
|
||||
|
||||
snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
|
||||
snprintf(value, sizeof(value),
|
||||
"+refs/heads/*:%s*", branch_top);
|
||||
git_config_set_multivar(key, value, "^$", 0);
|
||||
}
|
||||
|
||||
refspec.force = 0;
|
||||
refspec.pattern = 1;
|
||||
refspec.src = "refs/heads/";
|
||||
refspec.dst = branch_top;
|
||||
|
||||
if (path && !is_bundle)
|
||||
refs = clone_local(path, git_dir);
|
||||
else {
|
||||
struct remote *remote = remote_get(argv[0]);
|
||||
struct transport *transport = transport_get(remote, argv[0]);
|
||||
|
||||
if (!transport->get_refs_list || !transport->fetch)
|
||||
die("Don't know how to clone %s", transport->url);
|
||||
|
||||
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
|
||||
|
||||
if (option_depth)
|
||||
transport_set_option(transport, TRANS_OPT_DEPTH,
|
||||
option_depth);
|
||||
|
||||
if (option_quiet)
|
||||
transport->verbose = -1;
|
||||
|
||||
refs = transport_get_remote_refs(transport);
|
||||
transport_fetch_refs(transport, refs);
|
||||
}
|
||||
|
||||
clear_extra_refs();
|
||||
|
||||
mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
|
||||
|
||||
head_points_at = locate_head(refs, mapped_refs, &remote_head);
|
||||
|
||||
if (head_points_at) {
|
||||
/* Local default branch link */
|
||||
create_symref("HEAD", head_points_at->name, NULL);
|
||||
|
||||
if (!option_bare) {
|
||||
struct strbuf head_ref;
|
||||
const char *head = head_points_at->name;
|
||||
|
||||
if (!prefixcmp(head, "refs/heads/"))
|
||||
head += 11;
|
||||
|
||||
/* Set up the initial local branch */
|
||||
|
||||
/* Local branch initial value */
|
||||
update_ref(reflog_msg.buf, "HEAD",
|
||||
head_points_at->old_sha1,
|
||||
NULL, 0, DIE_ON_ERR);
|
||||
|
||||
strbuf_init(&head_ref, 0);
|
||||
strbuf_addstr(&head_ref, branch_top);
|
||||
strbuf_addstr(&head_ref, "HEAD");
|
||||
|
||||
/* Remote branch link */
|
||||
create_symref(head_ref.buf,
|
||||
head_points_at->peer_ref->name,
|
||||
reflog_msg.buf);
|
||||
|
||||
snprintf(key, sizeof(key), "branch.%s.remote", head);
|
||||
git_config_set(key, option_origin);
|
||||
snprintf(key, sizeof(key), "branch.%s.merge", head);
|
||||
git_config_set(key, head_points_at->name);
|
||||
}
|
||||
} else if (remote_head) {
|
||||
/* Source had detached HEAD pointing somewhere. */
|
||||
if (!option_bare)
|
||||
update_ref(reflog_msg.buf, "HEAD",
|
||||
remote_head->old_sha1,
|
||||
NULL, REF_NODEREF, DIE_ON_ERR);
|
||||
} else {
|
||||
/* Nothing to checkout out */
|
||||
if (!option_no_checkout)
|
||||
warning("remote HEAD refers to nonexistent ref, "
|
||||
"unable to checkout.\n");
|
||||
option_no_checkout = 1;
|
||||
}
|
||||
|
||||
if (!option_no_checkout) {
|
||||
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||
struct unpack_trees_options opts;
|
||||
struct tree *tree;
|
||||
struct tree_desc t;
|
||||
int fd;
|
||||
|
||||
/* We need to be in the new work tree for the checkout */
|
||||
setup_work_tree();
|
||||
|
||||
fd = hold_locked_index(lock_file, 1);
|
||||
|
||||
memset(&opts, 0, sizeof opts);
|
||||
opts.update = 1;
|
||||
opts.merge = 1;
|
||||
opts.fn = oneway_merge;
|
||||
opts.verbose_update = !option_quiet;
|
||||
opts.src_index = &the_index;
|
||||
opts.dst_index = &the_index;
|
||||
|
||||
tree = parse_tree_indirect(remote_head->old_sha1);
|
||||
parse_tree(tree);
|
||||
init_tree_desc(&t, tree->buffer, tree->size);
|
||||
unpack_trees(1, &t, &opts);
|
||||
|
||||
if (write_cache(fd, active_cache, active_nr) ||
|
||||
commit_locked_index(lock_file))
|
||||
die("unable to write new index file");
|
||||
}
|
||||
|
||||
strbuf_release(&reflog_msg);
|
||||
junk_pid = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -179,9 +179,10 @@ static void add_remove_files(struct path_list *list)
|
||||
struct stat st;
|
||||
struct path_list_item *p = &(list->items[i]);
|
||||
|
||||
if (!lstat(p->path, &st))
|
||||
add_to_cache(p->path, &st, 0);
|
||||
else
|
||||
if (!lstat(p->path, &st)) {
|
||||
if (add_to_cache(p->path, &st, 0))
|
||||
die("updating files failed");
|
||||
} else
|
||||
remove_file_from_cache(p->path);
|
||||
}
|
||||
}
|
||||
@@ -222,6 +223,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (interactive) {
|
||||
interactive_add(argc, argv, prefix);
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
commit_style = COMMIT_AS_IS;
|
||||
return get_index_file();
|
||||
}
|
||||
@@ -246,7 +249,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
if (all || (also && pathspec && *pathspec)) {
|
||||
int fd = hold_locked_index(&index_lock, 1);
|
||||
add_files_to_cache(0, also ? prefix : NULL, pathspec);
|
||||
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
if (write_cache(fd, active_cache, active_nr) ||
|
||||
close_lock_file(&index_lock))
|
||||
@@ -805,7 +808,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
|
||||
const char *index_file;
|
||||
int commitable;
|
||||
|
||||
git_config(git_status_config);
|
||||
git_config(git_status_config, NULL);
|
||||
|
||||
if (wt_status_use_color == -1)
|
||||
wt_status_use_color = git_use_color_default;
|
||||
@@ -859,7 +862,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
}
|
||||
}
|
||||
|
||||
int git_commit_config(const char *k, const char *v)
|
||||
int git_commit_config(const char *k, const char *v, void *cb)
|
||||
{
|
||||
if (!strcmp(k, "commit.template")) {
|
||||
if (!v)
|
||||
@@ -868,7 +871,7 @@ int git_commit_config(const char *k, const char *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_status_config(k, v);
|
||||
return git_status_config(k, v, cb);
|
||||
}
|
||||
|
||||
static const char commit_utf8_warn[] =
|
||||
@@ -880,10 +883,19 @@ static void add_parent(struct strbuf *sb, const unsigned char *sha1)
|
||||
{
|
||||
struct object *obj = parse_object(sha1);
|
||||
const char *parent = sha1_to_hex(sha1);
|
||||
const char *cp;
|
||||
|
||||
if (!obj)
|
||||
die("Unable to find commit parent %s", parent);
|
||||
if (obj->type != OBJ_COMMIT)
|
||||
die("Parent %s isn't a proper commit", parent);
|
||||
|
||||
for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) {
|
||||
if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') {
|
||||
error("duplicate parent %s ignored", parent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
strbuf_addf(sb, "parent %s\n", parent);
|
||||
}
|
||||
|
||||
@@ -896,7 +908,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
unsigned char commit_sha1[20];
|
||||
struct ref_lock *ref_lock;
|
||||
|
||||
git_config(git_commit_config);
|
||||
git_config(git_commit_config, NULL);
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_commit_usage);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -10,26 +10,54 @@
|
||||
#include "builtin.h"
|
||||
|
||||
static const char diff_files_usage[] =
|
||||
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|--no-index] [<common diff options>] [<path>...]"
|
||||
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
|
||||
COMMON_DIFF_OPTIONS_HELP;
|
||||
|
||||
int cmd_diff_files(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
int nongit;
|
||||
int result;
|
||||
unsigned options = 0;
|
||||
|
||||
prefix = setup_git_directory_gently(&nongit);
|
||||
init_revisions(&rev, prefix);
|
||||
git_config(git_diff_basic_config); /* no "diff" UI options */
|
||||
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
|
||||
rev.abbrev = 0;
|
||||
|
||||
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
|
||||
argc = 0;
|
||||
else
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
while (1 < argc && argv[1][0] == '-') {
|
||||
if (!strcmp(argv[1], "--base"))
|
||||
rev.max_count = 1;
|
||||
else if (!strcmp(argv[1], "--ours"))
|
||||
rev.max_count = 2;
|
||||
else if (!strcmp(argv[1], "--theirs"))
|
||||
rev.max_count = 3;
|
||||
else if (!strcmp(argv[1], "-q"))
|
||||
options |= DIFF_SILENT_ON_REMOVED;
|
||||
else
|
||||
usage(diff_files_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
if (!rev.diffopt.output_format)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
result = run_diff_files_cmd(&rev, argc, argv);
|
||||
|
||||
/*
|
||||
* Make sure there are NO revision (i.e. pending object) parameter,
|
||||
* rev.max_count is reasonable (0 <= n <= 3), and
|
||||
* there is no other revision filtering parameters.
|
||||
*/
|
||||
if (rev.pending.nr ||
|
||||
rev.min_age != -1 || rev.max_age != -1 ||
|
||||
3 < rev.max_count)
|
||||
usage(diff_files_usage);
|
||||
|
||||
if (rev.max_count == -1 &&
|
||||
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
|
||||
rev.combine_merges = rev.dense_combined_merges = 1;
|
||||
|
||||
if (read_cache() < 0) {
|
||||
perror("read_cache");
|
||||
return -1;
|
||||
}
|
||||
result = run_diff_files(&rev, options);
|
||||
return diff_result_code(&rev.diffopt, result);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -202,6 +202,37 @@ static void refresh_index_quietly(void)
|
||||
rollback_lock_file(lock_file);
|
||||
}
|
||||
|
||||
static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
|
||||
{
|
||||
int result;
|
||||
unsigned int options = 0;
|
||||
|
||||
while (1 < argc && argv[1][0] == '-') {
|
||||
if (!strcmp(argv[1], "--base"))
|
||||
revs->max_count = 1;
|
||||
else if (!strcmp(argv[1], "--ours"))
|
||||
revs->max_count = 2;
|
||||
else if (!strcmp(argv[1], "--theirs"))
|
||||
revs->max_count = 3;
|
||||
else if (!strcmp(argv[1], "-q"))
|
||||
options |= DIFF_SILENT_ON_REMOVED;
|
||||
else
|
||||
return error("invalid option: %s", argv[1]);
|
||||
argv++; argc--;
|
||||
}
|
||||
|
||||
if (revs->max_count == -1 &&
|
||||
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
|
||||
revs->combine_merges = revs->dense_combined_merges = 1;
|
||||
|
||||
if (read_cache() < 0) {
|
||||
perror("read_cache");
|
||||
return -1;
|
||||
}
|
||||
result = run_diff_files(revs, options);
|
||||
return diff_result_code(&revs->diffopt, result);
|
||||
}
|
||||
|
||||
int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@@ -230,31 +261,34 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
* N=2, M=0:
|
||||
* tree vs tree (diff-tree)
|
||||
*
|
||||
* N=0, M=0, P=2:
|
||||
* compare two filesystem entities (aka --no-index).
|
||||
*
|
||||
* Other cases are errors.
|
||||
*/
|
||||
|
||||
prefix = setup_git_directory_gently(&nongit);
|
||||
git_config(git_diff_ui_config);
|
||||
git_config(git_diff_ui_config, NULL);
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
|
||||
/* If this is a no-index diff, just run it and exit there. */
|
||||
diff_no_index(&rev, argc, argv, nongit, prefix);
|
||||
|
||||
/* Otherwise, we are doing the usual "git" diff */
|
||||
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
|
||||
|
||||
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
|
||||
argc = 0;
|
||||
else
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
if (nongit)
|
||||
die("Not a git repository");
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
if (!rev.diffopt.output_format) {
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
if (diff_setup_done(&rev.diffopt) < 0)
|
||||
die("diff_setup_done failed");
|
||||
}
|
||||
if (rev.diffopt.prefix && nongit) {
|
||||
rev.diffopt.prefix = NULL;
|
||||
rev.diffopt.prefix_length = 0;
|
||||
}
|
||||
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
|
||||
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
|
||||
|
||||
@@ -265,7 +299,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
|
||||
setup_pager();
|
||||
|
||||
/* Do we have --cached and not have a pending object, then
|
||||
/*
|
||||
* Do we have --cached and not have a pending object, then
|
||||
* default to HEAD by hand. Eek.
|
||||
*/
|
||||
if (!rev.pending.nr) {
|
||||
@@ -333,7 +368,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
if (!ents) {
|
||||
switch (blobs) {
|
||||
case 0:
|
||||
result = run_diff_files_cmd(&rev, argc, argv);
|
||||
result = builtin_diff_files(&rev, argc, argv);
|
||||
break;
|
||||
case 1:
|
||||
if (paths != 1)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -636,7 +636,7 @@ static int remove_duplicates(int nr_heads, char **heads)
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int fetch_pack_config(const char *var, const char *value)
|
||||
static int fetch_pack_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (strcmp(var, "fetch.unpacklimit") == 0) {
|
||||
fetch_unpack_limit = git_config_int(var, value);
|
||||
@@ -648,7 +648,7 @@ static int fetch_pack_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static struct lock_file lock;
|
||||
@@ -658,7 +658,7 @@ static void fetch_pack_setup(void)
|
||||
static int did_setup;
|
||||
if (did_setup)
|
||||
return;
|
||||
git_config(fetch_pack_config);
|
||||
git_config(fetch_pack_config, NULL);
|
||||
if (0 <= transfer_unpack_limit)
|
||||
unpack_limit = transfer_unpack_limit;
|
||||
else if (0 <= fetch_unpack_limit)
|
||||
|
||||
@@ -127,14 +127,8 @@ static struct ref *get_ref_map(struct transport *transport,
|
||||
/* Merge everything on the command line, but not --tags */
|
||||
for (rm = ref_map; rm; rm = rm->next)
|
||||
rm->merge = 1;
|
||||
if (tags == TAGS_SET) {
|
||||
struct refspec refspec;
|
||||
refspec.src = "refs/tags/";
|
||||
refspec.dst = "refs/tags/";
|
||||
refspec.pattern = 1;
|
||||
refspec.force = 0;
|
||||
get_fetch_map(remote_refs, &refspec, &tail, 0);
|
||||
}
|
||||
if (tags == TAGS_SET)
|
||||
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
|
||||
} else {
|
||||
/* Use the defaults */
|
||||
struct remote *remote = transport->remote;
|
||||
@@ -292,7 +286,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
|
||||
{
|
||||
FILE *fp;
|
||||
struct commit *commit;
|
||||
int url_len, i, note_len, shown_url = 0;
|
||||
int url_len, i, note_len, shown_url = 0, rc = 0;
|
||||
char note[1024];
|
||||
const char *what, *kind;
|
||||
struct ref *rm;
|
||||
@@ -359,7 +353,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
|
||||
note);
|
||||
|
||||
if (ref)
|
||||
update_local_ref(ref, what, verbose, note);
|
||||
rc |= update_local_ref(ref, what, verbose, note);
|
||||
else
|
||||
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
|
||||
SUMMARY_WIDTH, *kind ? kind : "branch",
|
||||
@@ -374,7 +368,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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,122 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
git_config_set("receive.denyNonFastforwards", "true");
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
if (!(flags & INIT_DB_QUIET))
|
||||
printf("%s%s Git repository in %s/\n",
|
||||
reinit ? "Reinitialized existing" : "Initialized empty",
|
||||
shared_repository ? " shared" : "",
|
||||
git_dir);
|
||||
get_git_dir());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int guess_repository_type(const char *git_dir)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
const char *slash;
|
||||
|
||||
/*
|
||||
* "GIT_DIR=. git init" is always bare.
|
||||
* "GIT_DIR=`pwd` git init" too.
|
||||
*/
|
||||
if (!strcmp(".", git_dir))
|
||||
return 1;
|
||||
if (!getcwd(cwd, sizeof(cwd)))
|
||||
die("cannot tell cwd");
|
||||
if (!strcmp(git_dir, cwd))
|
||||
return 1;
|
||||
/*
|
||||
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
|
||||
*/
|
||||
if (!strcmp(git_dir, ".git"))
|
||||
return 0;
|
||||
slash = strrchr(git_dir, '/');
|
||||
if (slash && !strcmp(slash, "/.git"))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Otherwise it is often bare. At this point
|
||||
* we are just guessing.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char init_db_usage[] =
|
||||
"git-init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
|
||||
|
||||
/*
|
||||
* If you want to, you can share the DB area with any number of branches.
|
||||
* That has advantages: you can save space by sharing all the SHA1 objects.
|
||||
* On the other hand, it might just make lookup slower and messier. You
|
||||
* be the judge. The default case is to have one DB per managed directory.
|
||||
*/
|
||||
int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *git_dir;
|
||||
const char *template_dir = NULL;
|
||||
unsigned int flags = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++, argv++) {
|
||||
const char *arg = argv[1];
|
||||
if (!prefixcmp(arg, "--template="))
|
||||
template_dir = arg+11;
|
||||
else if (!strcmp(arg, "--bare")) {
|
||||
static char git_dir[PATH_MAX+1];
|
||||
is_bare_repository_cfg = 1;
|
||||
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
|
||||
sizeof(git_dir)), 0);
|
||||
} else if (!strcmp(arg, "--shared"))
|
||||
shared_repository = PERM_GROUP;
|
||||
else if (!prefixcmp(arg, "--shared="))
|
||||
shared_repository = git_config_perm("arg", arg+9);
|
||||
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
|
||||
flags |= INIT_DB_QUIET;
|
||||
else
|
||||
usage(init_db_usage);
|
||||
}
|
||||
|
||||
/*
|
||||
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
|
||||
* without --bare. Catch the error early.
|
||||
*/
|
||||
git_dir = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if ((!git_dir || is_bare_repository_cfg == 1)
|
||||
&& getenv(GIT_WORK_TREE_ENVIRONMENT))
|
||||
die("%s (or --work-tree=<directory>) not allowed without "
|
||||
"specifying %s (or --git-dir=<directory>)",
|
||||
GIT_WORK_TREE_ENVIRONMENT,
|
||||
GIT_DIR_ENVIRONMENT);
|
||||
|
||||
/*
|
||||
* Set up the default .git directory contents
|
||||
*/
|
||||
if (!git_dir)
|
||||
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
||||
|
||||
if (is_bare_repository_cfg < 0)
|
||||
is_bare_repository_cfg = guess_repository_type(git_dir);
|
||||
|
||||
if (!is_bare_repository_cfg) {
|
||||
if (git_dir) {
|
||||
const char *git_dir_parent = strrchr(git_dir, '/');
|
||||
if (git_dir_parent) {
|
||||
char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
|
||||
git_work_tree_cfg = xstrdup(make_absolute_path(rel));
|
||||
free(rel);
|
||||
}
|
||||
}
|
||||
if (!git_work_tree_cfg) {
|
||||
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
|
||||
if (!getcwd(git_work_tree_cfg, PATH_MAX))
|
||||
die ("Cannot access current working directory.");
|
||||
}
|
||||
if (access(get_git_work_tree(), X_OK))
|
||||
die ("Cannot access work tree '%s'",
|
||||
get_git_work_tree());
|
||||
}
|
||||
|
||||
set_git_dir(make_absolute_path(git_dir));
|
||||
|
||||
return init_db(template_dir, flags);
|
||||
}
|
||||
|
||||
@@ -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,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
|
||||
for (i = 0; i < added.nr; i++) {
|
||||
const char *path = added.items[i].path;
|
||||
add_file_to_cache(path, verbose);
|
||||
if (add_file_to_cache(path, verbose ? ADD_CACHE_VERBOSE : 0))
|
||||
die("updating index entries failed");
|
||||
}
|
||||
|
||||
for (i = 0; i < deleted.nr; i++)
|
||||
|
||||
@@ -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 {
|
||||
@@ -43,6 +44,7 @@ struct object_entry {
|
||||
*/
|
||||
void *delta_data; /* cached delta (uncompressed) */
|
||||
unsigned long delta_size; /* delta data size (uncompressed) */
|
||||
unsigned long z_delta_size; /* delta data size (compressed) */
|
||||
unsigned int hash; /* name hint hash */
|
||||
enum object_type type;
|
||||
enum object_type in_pack_type; /* could be delta */
|
||||
@@ -65,7 +67,8 @@ static struct pack_idx_entry **written_list;
|
||||
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
|
||||
|
||||
static int non_empty;
|
||||
static int no_reuse_delta, no_reuse_object, keep_unreachable, include_tag;
|
||||
static int reuse_delta = 1, reuse_object = 1;
|
||||
static int keep_unreachable, unpack_unreachable, include_tag;
|
||||
static int local;
|
||||
static int incremental;
|
||||
static int allow_ofs_delta;
|
||||
@@ -102,24 +105,53 @@ static uint32_t written, written_delta;
|
||||
static uint32_t reused, reused_delta;
|
||||
|
||||
|
||||
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
|
||||
static void *get_delta(struct object_entry *entry)
|
||||
{
|
||||
unsigned long othersize, delta_size;
|
||||
unsigned long size, base_size, delta_size;
|
||||
void *buf, *base_buf, *delta_buf;
|
||||
enum object_type type;
|
||||
void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
|
||||
void *delta_buf;
|
||||
|
||||
if (!otherbuf)
|
||||
buf = read_sha1_file(entry->idx.sha1, &type, &size);
|
||||
if (!buf)
|
||||
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
|
||||
base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size);
|
||||
if (!base_buf)
|
||||
die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
|
||||
delta_buf = diff_delta(otherbuf, othersize,
|
||||
delta_buf = diff_delta(base_buf, base_size,
|
||||
buf, size, &delta_size, 0);
|
||||
if (!delta_buf || delta_size != entry->delta_size)
|
||||
if (!delta_buf || delta_size != entry->delta_size)
|
||||
die("delta size changed");
|
||||
free(buf);
|
||||
free(otherbuf);
|
||||
free(buf);
|
||||
free(base_buf);
|
||||
return delta_buf;
|
||||
}
|
||||
|
||||
static unsigned long do_compress(void **pptr, unsigned long size)
|
||||
{
|
||||
z_stream stream;
|
||||
void *in, *out;
|
||||
unsigned long maxsize;
|
||||
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
deflateInit(&stream, pack_compression_level);
|
||||
maxsize = deflateBound(&stream, size);
|
||||
|
||||
in = *pptr;
|
||||
out = xmalloc(maxsize);
|
||||
*pptr = out;
|
||||
|
||||
stream.next_in = in;
|
||||
stream.avail_in = size;
|
||||
stream.next_out = out;
|
||||
stream.avail_out = maxsize;
|
||||
while (deflate(&stream, Z_FINISH) == Z_OK)
|
||||
; /* nothing */
|
||||
deflateEnd(&stream);
|
||||
|
||||
free(in);
|
||||
return stream.total_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The per-object header is a pretty dense thing, which is
|
||||
* - first byte: low four bits are "size", then three bits of "type",
|
||||
@@ -222,42 +254,42 @@ static unsigned long write_object(struct sha1file *f,
|
||||
struct object_entry *entry,
|
||||
off_t write_offset)
|
||||
{
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
unsigned long size, limit, datalen;
|
||||
void *buf;
|
||||
unsigned char header[10];
|
||||
unsigned char dheader[10];
|
||||
unsigned char header[10], dheader[10];
|
||||
unsigned hdrlen;
|
||||
off_t datalen;
|
||||
enum object_type obj_type;
|
||||
int to_reuse = 0;
|
||||
/* write limit if limited packsize and not first object */
|
||||
unsigned long limit = pack_size_limit && nr_written ?
|
||||
pack_size_limit - write_offset : 0;
|
||||
/* no if no delta */
|
||||
int usable_delta = !entry->delta ? 0 :
|
||||
/* yes if unlimited packfile */
|
||||
!pack_size_limit ? 1 :
|
||||
/* no if base written to previous pack */
|
||||
entry->delta->idx.offset == (off_t)-1 ? 0 :
|
||||
/* otherwise double-check written to this
|
||||
* pack, like we do below
|
||||
*/
|
||||
entry->delta->idx.offset ? 1 : 0;
|
||||
enum object_type type;
|
||||
int usable_delta, to_reuse;
|
||||
|
||||
if (!pack_to_stdout)
|
||||
crc32_begin(f);
|
||||
|
||||
obj_type = entry->type;
|
||||
if (no_reuse_object)
|
||||
type = entry->type;
|
||||
|
||||
/* write limit if limited packsize and not first object */
|
||||
limit = pack_size_limit && nr_written ?
|
||||
pack_size_limit - write_offset : 0;
|
||||
|
||||
if (!entry->delta)
|
||||
usable_delta = 0; /* no delta */
|
||||
else if (!pack_size_limit)
|
||||
usable_delta = 1; /* unlimited packfile */
|
||||
else if (entry->delta->idx.offset == (off_t)-1)
|
||||
usable_delta = 0; /* base was written to another pack */
|
||||
else if (entry->delta->idx.offset)
|
||||
usable_delta = 1; /* base already exists in this pack */
|
||||
else
|
||||
usable_delta = 0; /* base could end up in another pack */
|
||||
|
||||
if (!reuse_object)
|
||||
to_reuse = 0; /* explicit */
|
||||
else if (!entry->in_pack)
|
||||
to_reuse = 0; /* can't reuse what we don't have */
|
||||
else if (obj_type == OBJ_REF_DELTA || obj_type == OBJ_OFS_DELTA)
|
||||
else if (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA)
|
||||
/* check_object() decided it for us ... */
|
||||
to_reuse = usable_delta;
|
||||
/* ... but pack split may override that */
|
||||
else if (obj_type != entry->in_pack_type)
|
||||
else if (type != entry->in_pack_type)
|
||||
to_reuse = 0; /* pack has delta which is unusable */
|
||||
else if (entry->delta)
|
||||
to_reuse = 0; /* we want to pack afresh */
|
||||
@@ -267,50 +299,42 @@ static unsigned long write_object(struct sha1file *f,
|
||||
*/
|
||||
|
||||
if (!to_reuse) {
|
||||
z_stream stream;
|
||||
unsigned long maxsize;
|
||||
void *out;
|
||||
if (!usable_delta) {
|
||||
buf = read_sha1_file(entry->idx.sha1, &obj_type, &size);
|
||||
buf = read_sha1_file(entry->idx.sha1, &type, &size);
|
||||
if (!buf)
|
||||
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
|
||||
/*
|
||||
* make sure no cached delta data remains from a
|
||||
* previous attempt before a pack split occured.
|
||||
*/
|
||||
free(entry->delta_data);
|
||||
entry->delta_data = NULL;
|
||||
entry->z_delta_size = 0;
|
||||
} else if (entry->delta_data) {
|
||||
size = entry->delta_size;
|
||||
buf = entry->delta_data;
|
||||
entry->delta_data = NULL;
|
||||
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
} else {
|
||||
buf = read_sha1_file(entry->idx.sha1, &type, &size);
|
||||
if (!buf)
|
||||
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
|
||||
buf = delta_against(buf, size, entry);
|
||||
buf = get_delta(entry);
|
||||
size = entry->delta_size;
|
||||
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
}
|
||||
/* compress the data to store and put compressed length in datalen */
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
deflateInit(&stream, pack_compression_level);
|
||||
maxsize = deflateBound(&stream, size);
|
||||
out = xmalloc(maxsize);
|
||||
/* Compress it */
|
||||
stream.next_in = buf;
|
||||
stream.avail_in = size;
|
||||
stream.next_out = out;
|
||||
stream.avail_out = maxsize;
|
||||
while (deflate(&stream, Z_FINISH) == Z_OK)
|
||||
/* nothing */;
|
||||
deflateEnd(&stream);
|
||||
datalen = stream.total_out;
|
||||
|
||||
if (entry->z_delta_size)
|
||||
datalen = entry->z_delta_size;
|
||||
else
|
||||
datalen = do_compress(&buf, size);
|
||||
|
||||
/*
|
||||
* The object header is a byte of 'type' followed by zero or
|
||||
* more bytes of length.
|
||||
*/
|
||||
hdrlen = encode_header(obj_type, size, header);
|
||||
hdrlen = encode_header(type, size, header);
|
||||
|
||||
if (obj_type == OBJ_OFS_DELTA) {
|
||||
if (type == OBJ_OFS_DELTA) {
|
||||
/*
|
||||
* Deltas with relative base contain an additional
|
||||
* encoding of the relative offset for the delta
|
||||
@@ -322,20 +346,18 @@ static unsigned long write_object(struct sha1file *f,
|
||||
while (ofs >>= 7)
|
||||
dheader[--pos] = 128 | (--ofs & 127);
|
||||
if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
|
||||
free(out);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
sha1write(f, header, hdrlen);
|
||||
sha1write(f, dheader + pos, sizeof(dheader) - pos);
|
||||
hdrlen += sizeof(dheader) - pos;
|
||||
} else if (obj_type == OBJ_REF_DELTA) {
|
||||
} else if (type == OBJ_REF_DELTA) {
|
||||
/*
|
||||
* Deltas with a base reference contain
|
||||
* an additional 20 bytes for the base sha1.
|
||||
*/
|
||||
if (limit && hdrlen + 20 + datalen + 20 >= limit) {
|
||||
free(out);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
@@ -344,14 +366,12 @@ static unsigned long write_object(struct sha1file *f,
|
||||
hdrlen += 20;
|
||||
} else {
|
||||
if (limit && hdrlen + datalen + 20 >= limit) {
|
||||
free(out);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
sha1write(f, header, hdrlen);
|
||||
}
|
||||
sha1write(f, out, datalen);
|
||||
free(out);
|
||||
sha1write(f, buf, datalen);
|
||||
free(buf);
|
||||
}
|
||||
else {
|
||||
@@ -361,11 +381,11 @@ static unsigned long write_object(struct sha1file *f,
|
||||
off_t offset;
|
||||
|
||||
if (entry->delta) {
|
||||
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
reused_delta++;
|
||||
}
|
||||
hdrlen = encode_header(obj_type, entry->size, header);
|
||||
hdrlen = encode_header(type, entry->size, header);
|
||||
offset = entry->in_pack_offset;
|
||||
revidx = find_pack_revindex(p, offset);
|
||||
datalen = revidx[1].offset - offset;
|
||||
@@ -374,7 +394,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
|
||||
offset += entry->in_pack_header_size;
|
||||
datalen -= entry->in_pack_header_size;
|
||||
if (obj_type == OBJ_OFS_DELTA) {
|
||||
if (type == OBJ_OFS_DELTA) {
|
||||
off_t ofs = entry->idx.offset - entry->delta->idx.offset;
|
||||
unsigned pos = sizeof(dheader) - 1;
|
||||
dheader[pos] = ofs & 127;
|
||||
@@ -385,7 +405,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
sha1write(f, header, hdrlen);
|
||||
sha1write(f, dheader + pos, sizeof(dheader) - pos);
|
||||
hdrlen += sizeof(dheader) - pos;
|
||||
} else if (obj_type == OBJ_REF_DELTA) {
|
||||
} else if (type == OBJ_REF_DELTA) {
|
||||
if (limit && hdrlen + 20 + datalen + 20 >= limit)
|
||||
return 0;
|
||||
sha1write(f, header, hdrlen);
|
||||
@@ -452,11 +472,10 @@ static void write_pack_file(void)
|
||||
struct sha1file *f;
|
||||
off_t offset, offset_one, last_obj_offset = 0;
|
||||
struct pack_header hdr;
|
||||
int do_progress = progress >> pack_to_stdout;
|
||||
uint32_t nr_remaining = nr_result;
|
||||
time_t last_mtime = 0;
|
||||
|
||||
if (do_progress)
|
||||
if (progress > pack_to_stdout)
|
||||
progress_state = start_progress("Writing objects", nr_result);
|
||||
written_list = xmalloc(nr_objects * sizeof(*written_list));
|
||||
|
||||
@@ -495,11 +514,14 @@ static void write_pack_file(void)
|
||||
* Did we write the wrong # entries in the header?
|
||||
* If so, rewrite it like in fast-import
|
||||
*/
|
||||
if (pack_to_stdout || nr_written == nr_remaining) {
|
||||
sha1close(f, sha1, 1);
|
||||
if (pack_to_stdout) {
|
||||
sha1close(f, sha1, CSUM_CLOSE);
|
||||
} else if (nr_written == nr_remaining) {
|
||||
sha1close(f, sha1, CSUM_FSYNC);
|
||||
} else {
|
||||
int fd = sha1close(f, NULL, 0);
|
||||
fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
|
||||
fsync_or_die(fd, pack_tmp_name);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -1022,7 +1044,7 @@ static void check_object(struct object_entry *entry)
|
||||
unuse_pack(&w_curs);
|
||||
return;
|
||||
case OBJ_REF_DELTA:
|
||||
if (!no_reuse_delta && !entry->preferred_base)
|
||||
if (reuse_delta && !entry->preferred_base)
|
||||
base_ref = use_pack(p, &w_curs,
|
||||
entry->in_pack_offset + used, NULL);
|
||||
entry->in_pack_header_size = used + 20;
|
||||
@@ -1045,7 +1067,7 @@ static void check_object(struct object_entry *entry)
|
||||
die("delta base offset out of bound for %s",
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
ofs = entry->in_pack_offset - ofs;
|
||||
if (!no_reuse_delta && !entry->preferred_base) {
|
||||
if (reuse_delta && !entry->preferred_base) {
|
||||
struct revindex_entry *revidx;
|
||||
revidx = find_pack_revindex(p, ofs);
|
||||
base_ref = nth_packed_object_sha1(p, revidx->nr);
|
||||
@@ -1233,7 +1255,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
* We do not bother to try a delta that we discarded
|
||||
* on an earlier try, but only when reusing delta data.
|
||||
*/
|
||||
if (!no_reuse_delta && trg_entry->in_pack &&
|
||||
if (reuse_delta && trg_entry->in_pack &&
|
||||
trg_entry->in_pack == src_entry->in_pack &&
|
||||
trg_entry->in_pack_type != OBJ_REF_DELTA &&
|
||||
trg_entry->in_pack_type != OBJ_OFS_DELTA)
|
||||
@@ -1441,11 +1463,34 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
|
||||
best_base = other_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we decided to cache the delta data, then it is best
|
||||
* to compress it right away. First because we have to do
|
||||
* it anyway, and doing it here while we're threaded will
|
||||
* save a lot of time in the non threaded write phase,
|
||||
* as well as allow for caching more deltas within
|
||||
* the same cache size limit.
|
||||
* ...
|
||||
* But only if not writing to stdout, since in that case
|
||||
* the network is most likely throttling writes anyway,
|
||||
* and therefore it is best to go to the write phase ASAP
|
||||
* instead, as we can afford spending more time compressing
|
||||
* between writes at that moment.
|
||||
*/
|
||||
if (entry->delta_data && !pack_to_stdout) {
|
||||
entry->z_delta_size = do_compress(&entry->delta_data,
|
||||
entry->delta_size);
|
||||
cache_lock();
|
||||
delta_cache_size -= entry->delta_size;
|
||||
delta_cache_size += entry->z_delta_size;
|
||||
cache_unlock();
|
||||
}
|
||||
|
||||
/* if we made n a delta, and if n is already at max
|
||||
* depth, leaving it in the window is pointless. we
|
||||
* should evict it first.
|
||||
*/
|
||||
if (entry->delta && depth <= n->depth)
|
||||
if (entry->delta && max_depth <= n->depth)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -1688,7 +1733,7 @@ static void prepare_pack(int window, int depth)
|
||||
|
||||
if (entry->delta)
|
||||
/* This happens if we decided to reuse existing
|
||||
* delta from a pack. "!no_reuse_delta &&" is implied.
|
||||
* delta from a pack. "reuse_delta &&" is implied.
|
||||
*/
|
||||
continue;
|
||||
|
||||
@@ -1718,7 +1763,7 @@ static void prepare_pack(int window, int depth)
|
||||
free(delta_list);
|
||||
}
|
||||
|
||||
static int git_pack_config(const char *k, const char *v)
|
||||
static int git_pack_config(const char *k, const char *v, void *cb)
|
||||
{
|
||||
if(!strcmp(k, "pack.window")) {
|
||||
window = git_config_int(k, v);
|
||||
@@ -1771,7 +1816,7 @@ static int git_pack_config(const char *k, const char *v)
|
||||
pack_size_limit_cfg = git_config_ulong(k, v);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
return git_default_config(k, v, cb);
|
||||
}
|
||||
|
||||
static void read_object_list_from_stdin(void)
|
||||
@@ -1905,6 +1950,32 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
|
||||
free(in_pack.array);
|
||||
}
|
||||
|
||||
static void loosen_unused_packed_objects(struct rev_info *revs)
|
||||
{
|
||||
struct packed_git *p;
|
||||
uint32_t i;
|
||||
const unsigned char *sha1;
|
||||
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
for (i = 0; i < revs->num_ignore_packed; i++) {
|
||||
if (matches_pack_name(p, revs->ignore_packed[i]))
|
||||
break;
|
||||
}
|
||||
if (revs->num_ignore_packed <= i)
|
||||
continue;
|
||||
|
||||
if (open_pack_index(p))
|
||||
die("cannot open pack index");
|
||||
|
||||
for (i = 0; i < p->num_objects; i++) {
|
||||
sha1 = nth_packed_object_sha1(p, i);
|
||||
if (!locate_object_entry(sha1))
|
||||
if (force_object_loose(sha1, p->mtime))
|
||||
die("unable to force loose object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_object_list(int ac, const char **av)
|
||||
{
|
||||
struct rev_info revs;
|
||||
@@ -1939,6 +2010,8 @@ static void get_object_list(int ac, const char **av)
|
||||
|
||||
if (keep_unreachable)
|
||||
add_objects_in_unpacked_packs(&revs);
|
||||
if (unpack_unreachable)
|
||||
loosen_unused_packed_objects(&revs);
|
||||
}
|
||||
|
||||
static int adjust_perm(const char *path, mode_t mode)
|
||||
@@ -1963,7 +2036,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
|
||||
rp_ac = 2;
|
||||
|
||||
git_config(git_pack_config);
|
||||
git_config(git_pack_config, NULL);
|
||||
if (!pack_compression_seen && core_compression_seen)
|
||||
pack_compression_level = core_compression_level;
|
||||
|
||||
@@ -2050,11 +2123,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--no-reuse-delta", arg)) {
|
||||
no_reuse_delta = 1;
|
||||
reuse_delta = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--no-reuse-object", arg)) {
|
||||
no_reuse_object = no_reuse_delta = 1;
|
||||
reuse_object = reuse_delta = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--delta-base-offset", arg)) {
|
||||
@@ -2073,6 +2146,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
keep_unreachable = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--unpack-unreachable", arg)) {
|
||||
unpack_unreachable = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--include-tag", arg)) {
|
||||
include_tag = 1;
|
||||
continue;
|
||||
@@ -2138,6 +2215,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
if (!pack_to_stdout && thin)
|
||||
die("--thin cannot be used to build an indexable pack.");
|
||||
|
||||
if (keep_unreachable && unpack_unreachable)
|
||||
die("--keep-unreachable and --unpack-unreachable are incompatible.");
|
||||
|
||||
#ifdef THREADED_DELTA_SEARCH
|
||||
if (!delta_search_threads) /* --threads=0 means autodetect */
|
||||
delta_search_threads = online_cpus();
|
||||
|
||||
@@ -85,7 +85,6 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix)
|
||||
/* Handle arguments here .. */
|
||||
usage(prune_packed_usage);
|
||||
}
|
||||
sync();
|
||||
prune_packed_objects(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,6 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
mark_reachable_objects(&revs, 1);
|
||||
prune_object_dir(get_object_directory());
|
||||
|
||||
sync();
|
||||
prune_packed_objects(show_only);
|
||||
remove_temporary_files();
|
||||
return 0;
|
||||
|
||||
@@ -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;
|
||||
|
||||
100
builtin-remote.c
100
builtin-remote.c
@@ -153,7 +153,7 @@ struct branch_info {
|
||||
|
||||
static struct path_list branch_list;
|
||||
|
||||
static int config_read_branches(const char *key, const char *value)
|
||||
static int config_read_branches(const char *key, const char *value, void *cb)
|
||||
{
|
||||
if (!prefixcmp(key, "branch.")) {
|
||||
char *name;
|
||||
@@ -200,13 +200,12 @@ static void read_branches(void)
|
||||
{
|
||||
if (branch_list.nr)
|
||||
return;
|
||||
git_config(config_read_branches);
|
||||
git_config(config_read_branches, NULL);
|
||||
sort_path_list(&branch_list);
|
||||
}
|
||||
|
||||
struct ref_states {
|
||||
struct remote *remote;
|
||||
struct strbuf remote_prefix;
|
||||
struct path_list new, stale, tracked;
|
||||
};
|
||||
|
||||
@@ -262,36 +261,72 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)
|
||||
}
|
||||
free_refs(fetch_map);
|
||||
|
||||
strbuf_addf(&states->remote_prefix,
|
||||
"refs/remotes/%s/", states->remote->name);
|
||||
for_each_ref(handle_one_branch, states);
|
||||
sort_path_list(&states->stale);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct known_remote {
|
||||
struct known_remote *next;
|
||||
struct remote *remote;
|
||||
};
|
||||
|
||||
struct known_remotes {
|
||||
struct remote *to_delete;
|
||||
struct known_remote *list;
|
||||
};
|
||||
|
||||
static int add_known_remote(struct remote *remote, void *cb_data)
|
||||
{
|
||||
struct known_remotes *all = cb_data;
|
||||
struct known_remote *r;
|
||||
|
||||
if (!strcmp(all->to_delete->name, remote->name))
|
||||
return 0;
|
||||
|
||||
r = xmalloc(sizeof(*r));
|
||||
r->remote = remote;
|
||||
r->next = all->list;
|
||||
all->list = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct branches_for_remote {
|
||||
const char *prefix;
|
||||
struct remote *remote;
|
||||
struct path_list *branches;
|
||||
struct known_remotes *keep;
|
||||
};
|
||||
|
||||
static int add_branch_for_removal(const char *refname,
|
||||
const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct branches_for_remote *branches = cb_data;
|
||||
struct refspec refspec;
|
||||
struct path_list_item *item;
|
||||
struct known_remote *kr;
|
||||
|
||||
if (!prefixcmp(refname, branches->prefix)) {
|
||||
struct path_list_item *item;
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
if (remote_find_tracking(branches->remote, &refspec))
|
||||
return 0;
|
||||
|
||||
/* make sure that symrefs are deleted */
|
||||
if (flags & REF_ISSYMREF)
|
||||
return unlink(git_path(refname));
|
||||
|
||||
item = path_list_append(refname, branches->branches);
|
||||
item->util = xmalloc(20);
|
||||
hashcpy(item->util, sha1);
|
||||
/* don't delete a branch if another remote also uses it */
|
||||
for (kr = branches->keep->list; kr; kr = kr->next) {
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
if (!remote_find_tracking(kr->remote, &refspec))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make sure that symrefs are deleted */
|
||||
if (flags & REF_ISSYMREF)
|
||||
return unlink(git_path(refname));
|
||||
|
||||
item = path_list_append(refname, branches->branches);
|
||||
item->util = xmalloc(20);
|
||||
hashcpy(item->util, sha1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -316,8 +351,9 @@ static int rm(int argc, const char **argv)
|
||||
};
|
||||
struct remote *remote;
|
||||
struct strbuf buf;
|
||||
struct known_remotes known_remotes = { NULL, NULL };
|
||||
struct path_list branches = { NULL, 0, 0, 1 };
|
||||
struct branches_for_remote cb_data = { NULL, &branches };
|
||||
struct branches_for_remote cb_data = { NULL, &branches, &known_remotes };
|
||||
int i;
|
||||
|
||||
if (argc != 2)
|
||||
@@ -327,6 +363,9 @@ static int rm(int argc, const char **argv)
|
||||
if (!remote)
|
||||
die("No such remote: %s", argv[1]);
|
||||
|
||||
known_remotes.to_delete = remote;
|
||||
for_each_remote(add_known_remote, &known_remotes);
|
||||
|
||||
strbuf_init(&buf, 0);
|
||||
strbuf_addf(&buf, "remote.%s", remote->name);
|
||||
if (git_config_rename_section(buf.buf, NULL) < 1)
|
||||
@@ -355,9 +394,7 @@ static int rm(int argc, const char **argv)
|
||||
* the branches one by one, since for_each_ref() relies on cached
|
||||
* refs, which are invalidated when deleting a branch.
|
||||
*/
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
|
||||
cb_data.prefix = buf.buf;
|
||||
cb_data.remote = remote;
|
||||
i = for_each_ref(add_branch_for_removal, &cb_data);
|
||||
strbuf_release(&buf);
|
||||
|
||||
@@ -422,27 +459,10 @@ static int show_or_prune(int argc, const char **argv, int prune)
|
||||
states.remote->name);
|
||||
|
||||
if (prune) {
|
||||
struct strbuf buf;
|
||||
int prefix_len;
|
||||
|
||||
strbuf_init(&buf, 0);
|
||||
if (states.remote->fetch_refspec_nr == 1 &&
|
||||
states.remote->fetch->pattern &&
|
||||
!strcmp(states.remote->fetch->src,
|
||||
states.remote->fetch->dst))
|
||||
/* handle --mirror remote */
|
||||
strbuf_addstr(&buf, "refs/heads/");
|
||||
else
|
||||
strbuf_addf(&buf, "refs/remotes/%s/", *argv);
|
||||
prefix_len = buf.len;
|
||||
|
||||
for (i = 0; i < states.stale.nr; i++) {
|
||||
strbuf_setlen(&buf, prefix_len);
|
||||
strbuf_addstr(&buf, states.stale.items[i].path);
|
||||
result |= delete_ref(buf.buf, NULL);
|
||||
const char *refname = states.stale.items[i].util;
|
||||
result |= delete_ref(refname, NULL);
|
||||
}
|
||||
|
||||
strbuf_release(&buf);
|
||||
goto cleanup_states;
|
||||
}
|
||||
|
||||
@@ -514,7 +534,7 @@ struct remote_group {
|
||||
struct path_list *list;
|
||||
} remote_group;
|
||||
|
||||
static int get_remote_group(const char *key, const char *value)
|
||||
static int get_remote_group(const char *key, const char *value, void *cb)
|
||||
{
|
||||
if (!prefixcmp(key, "remotes.") &&
|
||||
!strcmp(key + 8, remote_group.name)) {
|
||||
@@ -546,7 +566,7 @@ static int update(int argc, const char **argv)
|
||||
remote_group.list = &list;
|
||||
for (i = 1; i < argc; i++) {
|
||||
remote_group.name = argv[i];
|
||||
result = git_config(get_remote_group);
|
||||
result = git_config(get_remote_group, NULL);
|
||||
}
|
||||
|
||||
if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default"))
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -49,13 +49,14 @@ static inline int is_merge(void)
|
||||
return !access(git_path("MERGE_HEAD"), F_OK);
|
||||
}
|
||||
|
||||
static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
|
||||
static int reset_index_file(const unsigned char *sha1, int is_hard_reset, int quiet)
|
||||
{
|
||||
int i = 0;
|
||||
const char *args[6];
|
||||
|
||||
args[i++] = "read-tree";
|
||||
args[i++] = "-v";
|
||||
if (!quiet)
|
||||
args[i++] = "-v";
|
||||
args[i++] = "--reset";
|
||||
if (is_hard_reset)
|
||||
args[i++] = "-u";
|
||||
@@ -182,11 +183,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
OPT_SET_INT(0, "hard", &reset_type,
|
||||
"reset HEAD, index and working tree", HARD),
|
||||
OPT_BOOLEAN('q', NULL, &quiet,
|
||||
"disable showing new HEAD in hard reset"),
|
||||
"disable showing new HEAD in hard reset and progress message"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
git_config(git_default_config);
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
argc = parse_options(argc, argv, options, git_reset_usage,
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
@@ -231,7 +232,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
if (is_merge() || read_cache() < 0 || unmerged_cache())
|
||||
die("Cannot do a soft reset in the middle of a merge.");
|
||||
}
|
||||
else if (reset_index_file(sha1, (reset_type == HARD)))
|
||||
else if (reset_index_file(sha1, (reset_type == HARD), quiet))
|
||||
die("Could not reset index file to revision '%s'.", rev);
|
||||
|
||||
/* Any resets update HEAD to the head being switched to,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "list-objects.h"
|
||||
#include "builtin.h"
|
||||
#include "log-tree.h"
|
||||
#include "graph.h"
|
||||
|
||||
/* bits #0-15 in revision.h */
|
||||
|
||||
@@ -58,26 +59,31 @@ static const char *header_prefix;
|
||||
static void finish_commit(struct commit *commit);
|
||||
static void show_commit(struct commit *commit)
|
||||
{
|
||||
graph_show_commit(revs.graph);
|
||||
|
||||
if (show_timestamp)
|
||||
printf("%lu ", commit->date);
|
||||
if (header_prefix)
|
||||
fputs(header_prefix, stdout);
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (commit->object.flags & UNINTERESTING)
|
||||
putchar('^');
|
||||
else if (revs.left_right) {
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
putchar('<');
|
||||
else
|
||||
putchar('>');
|
||||
|
||||
if (!revs.graph) {
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (commit->object.flags & UNINTERESTING)
|
||||
putchar('^');
|
||||
else if (revs.left_right) {
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
putchar('<');
|
||||
else
|
||||
putchar('>');
|
||||
}
|
||||
}
|
||||
if (revs.abbrev_commit && revs.abbrev)
|
||||
fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
|
||||
stdout);
|
||||
else
|
||||
fputs(sha1_to_hex(commit->object.sha1), stdout);
|
||||
if (revs.parents) {
|
||||
if (revs.print_parents) {
|
||||
struct commit_list *parents = commit->parents;
|
||||
while (parents) {
|
||||
printf(" %s", sha1_to_hex(parents->item->object.sha1));
|
||||
@@ -96,9 +102,48 @@ static void show_commit(struct commit *commit)
|
||||
pretty_print_commit(revs.commit_format, commit,
|
||||
&buf, revs.abbrev, NULL, NULL,
|
||||
revs.date_mode, 0);
|
||||
if (buf.len)
|
||||
printf("%s%c", buf.buf, hdr_termination);
|
||||
if (revs.graph) {
|
||||
if (buf.len) {
|
||||
if (revs.commit_format != CMIT_FMT_ONELINE)
|
||||
graph_show_oneline(revs.graph);
|
||||
|
||||
graph_show_commit_msg(revs.graph, &buf);
|
||||
|
||||
/*
|
||||
* Add a newline after the commit message.
|
||||
*
|
||||
* Usually, this newline produces a blank
|
||||
* padding line between entries, in which case
|
||||
* we need to add graph padding on this line.
|
||||
*
|
||||
* However, the commit message may not end in a
|
||||
* newline. In this case the newline simply
|
||||
* ends the last line of the commit message,
|
||||
* and we don't need any graph output. (This
|
||||
* always happens with CMIT_FMT_ONELINE, and it
|
||||
* happens with CMIT_FMT_USERFORMAT when the
|
||||
* format doesn't explicitly end in a newline.)
|
||||
*/
|
||||
if (buf.len && buf.buf[buf.len - 1] == '\n')
|
||||
graph_show_padding(revs.graph);
|
||||
putchar('\n');
|
||||
} else {
|
||||
/*
|
||||
* If the message buffer is empty, just show
|
||||
* the rest of the graph output for this
|
||||
* commit.
|
||||
*/
|
||||
if (graph_show_remainder(revs.graph))
|
||||
putchar('\n');
|
||||
}
|
||||
} else {
|
||||
if (buf.len)
|
||||
printf("%s%c", buf.buf, hdr_termination);
|
||||
}
|
||||
strbuf_release(&buf);
|
||||
} else {
|
||||
if (graph_show_remainder(revs.graph))
|
||||
putchar('\n');
|
||||
}
|
||||
maybe_flush_or_die(stdout, "stdout");
|
||||
finish_commit(commit);
|
||||
@@ -546,7 +591,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
int bisect_find_all = 0;
|
||||
int quiet = 0;
|
||||
|
||||
git_config(git_default_config);
|
||||
git_config(git_default_config, NULL);
|
||||
init_revisions(&revs, prefix);
|
||||
revs.abbrev = 0;
|
||||
revs.commit_format = CMIT_FMT_UNSPECIFIED;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user