mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
44
Documentation/RelNotes-1.5.5.1.txt
Normal file
44
Documentation/RelNotes-1.5.5.1.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
GIT v1.5.5.1 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.5
|
||||
------------------
|
||||
|
||||
* "git archive --prefix=$path/" mishandled gitattributes.
|
||||
|
||||
* "git fetch -v" that fetches into FETCH_HEAD did not report the summary
|
||||
the same way as done for updating the tracking refs.
|
||||
|
||||
* "git svn" misbehaved when the configuration file customized the "git
|
||||
log" output format using format.pretty.
|
||||
|
||||
* "git submodule status" leaked an unnecessary error message.
|
||||
|
||||
* "git log --date-order --topo-order" did not override the earlier
|
||||
date-order with topo-order as expected.
|
||||
|
||||
* "git bisect good $this" did not check the validity of the revision
|
||||
given properly.
|
||||
|
||||
* "url.<there>.insteadOf" did not work correctly.
|
||||
|
||||
* "git clean" ran inside subdirectory behaved as if the directory was
|
||||
explicitly specified for removal by the end user from the top level.
|
||||
|
||||
* "git bisect" from a detached head leaked an unnecessary error message.
|
||||
|
||||
* "git bisect good $a $b" when $a is Ok but $b is bogus should have
|
||||
atomically failed before marking $a as good.
|
||||
|
||||
* "git fmt-merge-msg" did not clean up leading empty lines from commit
|
||||
log messages like "git log" family does.
|
||||
|
||||
* "git am" recorded a commit with empty Subject: line without
|
||||
complaining.
|
||||
|
||||
* when given a commit log message whose first paragraph consists of
|
||||
multiple lines, "git rebase" squashed it into a single line.
|
||||
|
||||
* "git remote add $bogus_name $url" did not complain properly.
|
||||
|
||||
Also comes with various documentation updates.
|
||||
59
Documentation/RelNotes-1.5.6.txt
Normal file
59
Documentation/RelNotes-1.5.6.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
GIT v1.5.6 Release Notes
|
||||
========================
|
||||
|
||||
Updates since v1.5.5
|
||||
--------------------
|
||||
|
||||
(subsystems)
|
||||
|
||||
|
||||
(portability)
|
||||
|
||||
|
||||
(performance)
|
||||
|
||||
* "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.
|
||||
|
||||
(usability, bells and whistles)
|
||||
|
||||
* "git add -p" (and the "patch" subcommand of "git add -i") can choose to
|
||||
apply (or not apply) mode changes independently from contents changes.
|
||||
|
||||
* "git bisect help" gives longer and more helpful usage information.
|
||||
|
||||
* "git diff/log --dirstat" output is consistent between binary and textual
|
||||
changes.
|
||||
|
||||
* "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 send-email" now can send out messages outside a git repository.
|
||||
|
||||
* "git status" can optionally include output from "git submodule
|
||||
summary".
|
||||
|
||||
* "gitweb" can read from a system-wide configuration file.
|
||||
|
||||
(internal)
|
||||
|
||||
* "git unpack-objects" and "git receive-pack" is now more strict about
|
||||
detecting breakage in the objects they receive over the wire.
|
||||
|
||||
|
||||
Fixes since v1.5.5
|
||||
------------------
|
||||
|
||||
All of the fixes in v1.5.5 maintenance series are included in
|
||||
this release, unless otherwise noted.
|
||||
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.5-56-g5f0734f
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
@@ -234,7 +234,13 @@ core.worktree::
|
||||
used in combination with repositories found automatically in
|
||||
a .git directory (i.e. $GIT_DIR is not set).
|
||||
This can be overridden by the GIT_WORK_TREE environment
|
||||
variable and the '--work-tree' command line option.
|
||||
variable and the '--work-tree' command line option. It can be
|
||||
a absolute path or relative path to the directory specified by
|
||||
--git-dir or GIT_DIR.
|
||||
Note: If --git-dir or GIT_DIR are specified but none of
|
||||
--work-tree, GIT_WORK_TREE and core.worktree is specified,
|
||||
the current working directory is regarded as the top directory
|
||||
of your working tree.
|
||||
|
||||
core.logAllRefUpdates::
|
||||
Enable the reflog. Updates to a ref <ref> is logged to the file
|
||||
@@ -261,7 +267,12 @@ core.sharedRepository::
|
||||
group-writable). When 'all' (or 'world' or 'everybody'), the
|
||||
repository will be readable by all users, additionally to being
|
||||
group-shareable. When 'umask' (or 'false'), git will use permissions
|
||||
reported by umask(2). See linkgit:git-init[1]. False by default.
|
||||
reported by umask(2). When '0xxx', where '0xxx' is an octal number,
|
||||
files in the repository will have this mode value. '0xxx' will override
|
||||
user's umask value, and thus, users with a safe umask (0077) can use
|
||||
this option. Examples: '0660' is equivalent to 'group'. '0640' is a
|
||||
repository that is group-readable but not group-writable.
|
||||
See linkgit:git-init[1]. False by default.
|
||||
|
||||
core.warnAmbiguousRefs::
|
||||
If true, git will warn you if the ref name you passed it is ambiguous
|
||||
@@ -991,6 +1002,12 @@ imap::
|
||||
The configuration variables in the 'imap' section are described
|
||||
in linkgit:git-imap-send[1].
|
||||
|
||||
receive.fsckObjects::
|
||||
If it is set to true, git-receive-pack will check all received
|
||||
objects. It will abort in the case of a malformed object or a
|
||||
broken link. The result of an abort are only dangling objects.
|
||||
Defaults to false.
|
||||
|
||||
receive.unpackLimit::
|
||||
If the number of objects received in a push is below this
|
||||
limit then the objects will be unpacked into loose object
|
||||
|
||||
@@ -535,18 +535,18 @@ with the associated patches use the more complex (and much more
|
||||
powerful)
|
||||
|
||||
----------------
|
||||
$ git-whatchanged -p --root
|
||||
$ git-whatchanged -p
|
||||
----------------
|
||||
|
||||
and you will see exactly what has changed in the repository over its
|
||||
short history.
|
||||
|
||||
[NOTE]
|
||||
The `\--root` flag is a flag to `git-diff-tree` to tell it to
|
||||
show the initial aka 'root' commit too. Normally you'd probably not
|
||||
want to see the initial import diff, but since the tutorial project
|
||||
was started from scratch and is so small, we use it to make the result
|
||||
a bit more interesting.
|
||||
When using the above two commands, the initial commit will be shown.
|
||||
If this is a problem because it is huge, you can hide it by setting
|
||||
the log.showroot configuration variable to false. Having this, you
|
||||
can still show it for each command just adding the `\--root` option,
|
||||
which is a flag for `git-diff-tree` accepted by both commands.
|
||||
|
||||
With that, you should now be having some inkling of what git does, and
|
||||
can explore on your own.
|
||||
|
||||
@@ -8,7 +8,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] should be sufficient.
|
||||
link:tutorial.html[tutorial introduction to git] and the
|
||||
link:glossary.html[git glossary] should be sufficient.
|
||||
|
||||
Developing against a shared repository
|
||||
--------------------------------------
|
||||
|
||||
@@ -58,6 +58,14 @@ endif::git-format-patch[]
|
||||
number of modified files, as well as number of added and deleted
|
||||
lines.
|
||||
|
||||
--dirstat[=limit]::
|
||||
Output only the sub-directories that are impacted by a diff,
|
||||
and to what degree they are impacted. You can override the
|
||||
default cut-off in percent (3) by "--dirstat=limit". If you
|
||||
want to enable "cumulative" directory statistics, you can use
|
||||
the "--cumulative" flag, which adds up percentages recursively
|
||||
even when they have been already reported for a sub-directory.
|
||||
|
||||
--summary::
|
||||
Output a condensed summary of extended header information
|
||||
such as creations, renames and mode changes.
|
||||
@@ -75,7 +83,8 @@ endif::git-format-patch[]
|
||||
Show only names of changed files.
|
||||
|
||||
--name-status::
|
||||
Show only names and status of changed files.
|
||||
Show only names and status of changed files. See the description
|
||||
of the `--diff-filter` option on what the status letters mean.
|
||||
|
||||
--color::
|
||||
Show colored diff.
|
||||
|
||||
@@ -48,14 +48,12 @@ $ git gc <3>
|
||||
repository health reasonably well.
|
||||
<2> check how many loose objects there are and how much
|
||||
disk space is wasted by not repacking.
|
||||
<3> repacks the local repository and performs other housekeeping tasks. Running
|
||||
without `--prune` is a safe operation even while other ones are in progress.
|
||||
<3> repacks the local repository and performs other housekeeping tasks.
|
||||
|
||||
Repack a small project into single pack.::
|
||||
+
|
||||
------------
|
||||
$ git gc <1>
|
||||
$ git gc --prune
|
||||
------------
|
||||
+
|
||||
<1> pack all the objects reachable from the refs into one pack,
|
||||
@@ -182,7 +180,7 @@ $ git pull <3>
|
||||
$ git log -p ORIG_HEAD.. arch/i386 include/asm-i386 <4>
|
||||
$ git pull git://git.kernel.org/pub/.../jgarzik/libata-dev.git ALL <5>
|
||||
$ git reset --hard ORIG_HEAD <6>
|
||||
$ git gc --prune <7>
|
||||
$ git gc <7>
|
||||
$ git fetch --tags <8>
|
||||
------------
|
||||
+
|
||||
|
||||
@@ -15,6 +15,7 @@ DESCRIPTION
|
||||
The command takes various subcommands, and different options depending
|
||||
on the subcommand:
|
||||
|
||||
git bisect help
|
||||
git bisect start [<bad> [<good>...]] [--] [<paths>...]
|
||||
git bisect bad [<rev>]
|
||||
git bisect good [<rev>...]
|
||||
@@ -29,6 +30,12 @@ This command uses 'git-rev-list --bisect' option to help drive the
|
||||
binary search process to find which change introduced a bug, given an
|
||||
old "good" commit object name and a later "bad" commit object name.
|
||||
|
||||
Getting help
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Use "git bisect" to get a short usage description, and "git bisect
|
||||
help" or "git bisect -h" to get a long usage description.
|
||||
|
||||
Basic bisect commands: start, bad, good
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ OPTIONS
|
||||
by linkgit:git-check-ref-format[1]. Some of these checks
|
||||
may restrict the characters allowed in a branch name.
|
||||
|
||||
--track::
|
||||
-t, --track::
|
||||
When creating a new branch, set up configuration so that git-pull
|
||||
will automatically retrieve data from the start point, which must be
|
||||
a branch. Use this if you always pull from the same upstream branch
|
||||
|
||||
@@ -65,10 +65,13 @@ OPTIONS
|
||||
+
|
||||
*NOTE*: this is a possibly dangerous operation; do *not* use
|
||||
it unless you understand what it does. If you clone your
|
||||
repository using this option, then delete branches in the
|
||||
source repository and then run linkgit:git-gc[1] using the
|
||||
'--prune' option in the source repository, it may remove
|
||||
objects which are referenced by the cloned repository.
|
||||
repository using this option and then delete branches (or use any
|
||||
other git command that makes any existing commit unreferenced) in the
|
||||
source repository, some objects may become unreferenced (or dangling).
|
||||
These objects may be removed by normal git operations (such as git-commit[1])
|
||||
which automatically call git-gc[1]. If these objects are removed and
|
||||
were referenced by the cloned repository, then the cloned repository
|
||||
will become corrupt.
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +82,8 @@ objects which are referenced by the cloned repository.
|
||||
an already existing repository as an alternate will
|
||||
require fewer objects to be copied from the repository
|
||||
being cloned, reducing network and local storage costs.
|
||||
+
|
||||
*NOTE*: see NOTE to --shared option.
|
||||
|
||||
--quiet::
|
||||
-q::
|
||||
|
||||
@@ -139,6 +139,17 @@ but can be used to amend a merge commit.
|
||||
as well. This is usually not what you want unless you
|
||||
are concluding a conflicted merge.
|
||||
|
||||
-o|--only::
|
||||
Make a commit only from the paths specified on the
|
||||
command line, disregarding any contents that have been
|
||||
staged so far. This is the default mode of operation of
|
||||
'git commit' if any paths are given on the command line,
|
||||
in which case this option can be omitted.
|
||||
If this option is specified together with '--amend', then
|
||||
no paths need be specified, which can be used to amend
|
||||
the last commit without committing changes that have
|
||||
already been staged.
|
||||
|
||||
-u|--untracked-files::
|
||||
Show all untracked files, also those in uninteresting
|
||||
directories, in the "Untracked files:" section of commit
|
||||
|
||||
@@ -144,6 +144,8 @@ See also <<FILES>>.
|
||||
"auto". If `stdout-is-tty` is missing, then checks the standard
|
||||
output of the command itself, and exits with status 0 if color
|
||||
is to be used, or exits with status 1 otherwise.
|
||||
When the color setting for `name` is undefined, the command uses
|
||||
`color.ui` as fallback.
|
||||
|
||||
--get-color name default::
|
||||
|
||||
|
||||
@@ -110,7 +110,9 @@ cvs -d ":ext;CVS_SERVER=git-cvsserver:user@server/path/repo.git" co <HEAD_name>
|
||||
------
|
||||
This has the advantage that it will be saved in your 'CVS/Root' files and
|
||||
you don't need to worry about always setting the correct environment
|
||||
variable.
|
||||
variable. SSH users restricted to git-shell don't need to override the default
|
||||
with CVS_SERVER (and shouldn't) as git-shell understands `cvs` to mean
|
||||
git-cvsserver and pretends that the other end runs the real cvs better.
|
||||
--
|
||||
2. For each repo that you want accessible from CVS you need to edit config in
|
||||
the repo and add the following section.
|
||||
@@ -141,25 +143,29 @@ allowing access over SSH.
|
||||
enabled=1
|
||||
------
|
||||
--
|
||||
3. On the client machine you need to set the following variables.
|
||||
CVSROOT should be set as per normal, but the directory should point at the
|
||||
appropriate git repo. For example:
|
||||
3. If you didn't specify the CVSROOT/CVS_SERVER directly in the checkout command,
|
||||
automatically saving it in your 'CVS/Root' files, then you need to set them
|
||||
explicitly in your environment. CVSROOT should be set as per normal, but the
|
||||
directory should point at the appropriate git repo. As above, for SSH clients
|
||||
_not_ restricted to git-shell, CVS_SERVER should be set to git-cvsserver.
|
||||
+
|
||||
--
|
||||
For SSH access, CVS_SERVER should be set to git-cvsserver
|
||||
|
||||
Example:
|
||||
|
||||
------
|
||||
export CVSROOT=:ext:user@server:/var/git/project.git
|
||||
export CVS_SERVER=git-cvsserver
|
||||
------
|
||||
--
|
||||
4. For SSH clients that will make commits, make sure their .bashrc file
|
||||
sets the GIT_AUTHOR and GIT_COMMITTER variables.
|
||||
4. For SSH clients that will make commits, make sure their server-side
|
||||
.ssh/environment files (or .bashrc, etc., according to their specific shell)
|
||||
export appropriate values for GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL,
|
||||
GIT_COMMITTER_NAME, and GIT_COMMITTER_EMAIL. For SSH clients whose login
|
||||
shell is bash, .bashrc may be a reasonable alternative.
|
||||
|
||||
5. Clients should now be able to check out the project. Use the CVS 'module'
|
||||
name to indicate what GIT 'head' you want to check out. Example:
|
||||
name to indicate what GIT 'head' you want to check out. This also sets the
|
||||
name of your newly checked-out directory, unless you tell it otherwise with
|
||||
`-d <dir_name>`. For example, this checks out 'master' branch to the
|
||||
`project-master` directory:
|
||||
+
|
||||
------
|
||||
cvs co -d project-master master
|
||||
|
||||
@@ -22,7 +22,8 @@ OPTIONS
|
||||
An object to treat as the head of an unreachability trace.
|
||||
+
|
||||
If no objects are given, git-fsck defaults to using the
|
||||
index file and all SHA1 references in .git/refs/* as heads.
|
||||
index file, all SHA1 references in .git/refs/*, and all reflogs (unless
|
||||
--no-reflogs is given) as heads.
|
||||
|
||||
--unreachable::
|
||||
Print out objects that exist but that aren't readable from any
|
||||
|
||||
@@ -104,6 +104,21 @@ The optional configuration variable 'gc.pruneExpire' controls how old
|
||||
the unreferenced loose objects have to be before they are pruned. The
|
||||
default is "2 weeks ago".
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
git-gc tries very hard to be safe about the garbage it collects. In
|
||||
particular, it will keep not only objects referenced by your current set
|
||||
of branches and tags, but also objects referenced by the index, remote
|
||||
tracking branches, refs saved by linkgit:git-filter-branch[1] in
|
||||
refs/original/, or reflogs (which may references commits in branches
|
||||
that were later amended or rewound).
|
||||
|
||||
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
|
||||
--------
|
||||
linkgit:git-prune[1]
|
||||
|
||||
@@ -31,7 +31,7 @@ structure, some suggested "exclude patterns", and copies of non-executing
|
||||
"hook" files. The suggested patterns and hook files are all modifiable and
|
||||
extensible.
|
||||
|
||||
--shared[={false|true|umask|group|all|world|everybody}]::
|
||||
--shared[={false|true|umask|group|all|world|everybody|0xxx}]::
|
||||
|
||||
Specify that the git repository is to be shared amongst several users. This
|
||||
allows users belonging to the same group to push into that
|
||||
@@ -52,6 +52,12 @@ is given:
|
||||
- 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
|
||||
readable by all users.
|
||||
|
||||
- '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'
|
||||
Any option except 'umask' can be set using this option. '0xxx' will
|
||||
override users umask(2) value, and thus, users with a safe umask (0077)
|
||||
can use this option. '0640' will create a repository which is group-readable
|
||||
but not writable. '0660' is equivalent to 'group'.
|
||||
|
||||
By default, the configuration flag receive.denyNonFastForwards is enabled
|
||||
in shared repositories, so that you cannot force a non fast-forwarding push
|
||||
into it.
|
||||
|
||||
@@ -13,6 +13,9 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
NOTE: In most cases, users should run linkgit:git-gc[1], which calls
|
||||
git-prune. See the section "NOTES", below.
|
||||
|
||||
This runs `git-fsck --unreachable` using all the refs
|
||||
available in `$GIT_DIR/refs`, optionally with additional set of
|
||||
objects specified on the command line, and prunes all
|
||||
@@ -50,6 +53,23 @@ borrows from your repository via its
|
||||
$ git prune $(cd ../another && $(git-rev-parse --all))
|
||||
------------
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
In most cases, users will not need to call git-prune directly, but
|
||||
should instead call linkgit:git-gc[1], which handles pruning along with
|
||||
many other housekeeping tasks.
|
||||
|
||||
For a description of which objects are considered for pruning, see
|
||||
git-fsck's --unreachable option.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
linkgit:git-fsck[1],
|
||||
linkgit:git-gc[1],
|
||||
linkgit:git-reflog[1]
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
@@ -35,14 +35,15 @@ OPTIONS
|
||||
by the source ref, followed by a colon `:`, followed by
|
||||
the destination ref.
|
||||
+
|
||||
The <src> side can be an
|
||||
arbitrary "SHA1 expression" that can be used as an
|
||||
argument to `git-cat-file -t`. E.g. `master~4` (push
|
||||
four parents before the current master head).
|
||||
The <src> side represents the source branch (or arbitrary
|
||||
"SHA1 expression", such as `master~4` (four parents before the
|
||||
tip of `master` branch); see linkgit:git-rev-parse[1]) that you
|
||||
want to push. The <dst> side represents the destination location.
|
||||
+
|
||||
The local ref that matches <src> is used
|
||||
to fast forward the remote ref that matches <dst>. If
|
||||
the optional plus `+` is used, the remote ref is updated
|
||||
to fast forward the remote ref that matches <dst> (or, if no <dst> was
|
||||
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
|
||||
@@ -165,7 +166,8 @@ git push origin master::
|
||||
Find a ref that matches `master` in the source repository
|
||||
(most likely, it would find `refs/heads/master`), and update
|
||||
the same ref (e.g. `refs/heads/master`) in `origin` repository
|
||||
with it.
|
||||
with it. If `master` did not exist remotely, it would be
|
||||
created.
|
||||
|
||||
git push origin :experimental::
|
||||
Find a ref that matches `experimental` in the `origin` repository
|
||||
@@ -179,9 +181,10 @@ git push origin master:satellite/master::
|
||||
|
||||
git push origin master:refs/heads/experimental::
|
||||
Create the branch `experimental` in the `origin` repository
|
||||
by copying the current `master` branch. This form is usually
|
||||
needed to create a new branch in the remote repository as
|
||||
there is no `experimental` branch to match.
|
||||
by copying the current `master` branch. This form is only
|
||||
needed to create a new branch or tag in the remote repository when
|
||||
the local name and the remote name are different; otherwise,
|
||||
the ref name on its own will work.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -24,7 +24,7 @@ OPTIONS
|
||||
URL to include in the summary.
|
||||
|
||||
<end>::
|
||||
Commit to send at; defaults to HEAD.
|
||||
Commit to end at; defaults to HEAD.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -52,6 +52,11 @@ OPTIONS
|
||||
The parameter given must be usable as a single, valid
|
||||
object name. Otherwise barf and abort.
|
||||
|
||||
-q, --quiet::
|
||||
Only meaningful in `--verify` mode. Do not output an error
|
||||
message if the first argument is not a valid object name;
|
||||
instead exit with non-zero status silently.
|
||||
|
||||
--sq::
|
||||
Usually the output is made one line per flag and
|
||||
parameter. This option makes output a single line,
|
||||
|
||||
@@ -11,28 +11,37 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Remove files from the working tree and from the index. The
|
||||
files have to be identical to the tip of the branch, and no
|
||||
updates to its contents must have been placed in the staging
|
||||
area (aka index). When --cached is given, the staged content has to
|
||||
match either the tip of the branch *or* the file on disk.
|
||||
Remove files from the index, or from the working tree and the index.
|
||||
`git rm` will not remove a file from just your working directory.
|
||||
(There is no option to remove a file only from the work tree
|
||||
and yet keep it in the index; use `/bin/rm` if you want to do that.)
|
||||
The files being removed have to be identical to the tip of the branch,
|
||||
and no updates to their contents can be staged in the index,
|
||||
though that default behavior can be overridden with the `-f` option.
|
||||
When '--cached' is given, the staged content has to
|
||||
match either the tip of the branch or the file on disk,
|
||||
allowing the file to be removed from just the index.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<file>...::
|
||||
Files to remove. Fileglobs (e.g. `*.c`) can be given to
|
||||
remove all matching files. Also a leading directory name
|
||||
(e.g. `dir` to add `dir/file1` and `dir/file2`) can be
|
||||
given to remove all files in the directory, recursively,
|
||||
but this requires `-r` option to be given for safety.
|
||||
remove all matching files. If you want git to expand
|
||||
file glob characters, you may need to shell-escape them.
|
||||
A leading directory name
|
||||
(e.g. `dir` to remove `dir/file1` and `dir/file2`) can be
|
||||
given to remove all files in the directory, and recursively
|
||||
all sub-directories,
|
||||
but this requires the `-r` option to be explicitly given.
|
||||
|
||||
-f::
|
||||
Override the up-to-date check.
|
||||
|
||||
-n, \--dry-run::
|
||||
Don't actually remove the file(s), just show if they exist in
|
||||
the index.
|
||||
Don't actually remove any file(s). Instead, just show
|
||||
if they exist in the index and would otherwise be removed
|
||||
by the command.
|
||||
|
||||
-r::
|
||||
Allow recursive removal when a leading directory name is
|
||||
@@ -44,9 +53,9 @@ OPTIONS
|
||||
for command-line options).
|
||||
|
||||
\--cached::
|
||||
This option can be used to tell the command to remove
|
||||
the paths only from the index, leaving working tree
|
||||
files.
|
||||
Use this option to unstage and remove paths only from the index.
|
||||
Working tree files, whether modified or not, will be
|
||||
left alone.
|
||||
|
||||
\--ignore-unmatch::
|
||||
Exit with a zero status even if no files matched.
|
||||
@@ -59,11 +68,15 @@ OPTIONS
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
The list of <file> given to the command can be exact pathnames,
|
||||
file glob patterns, or leading directory name. The command
|
||||
removes only the paths that is known to git. Giving the name of
|
||||
The <file> list given to the command can be exact pathnames,
|
||||
file glob patterns, or leading directory names. The command
|
||||
removes only the paths that are known to git. Giving the name of
|
||||
a file that you have not told git about does not remove that file.
|
||||
|
||||
File globbing matches across directory boundaries. Thus, given
|
||||
two directories `d` and `d2`, there is a difference between
|
||||
using `git rm \'d\*\'` and `git rm \'d/\*\'`, as the former will
|
||||
also remove all of directory `d2`.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
@@ -72,11 +85,10 @@ git-rm Documentation/\\*.txt::
|
||||
`Documentation` directory and any of its subdirectories.
|
||||
+
|
||||
Note that the asterisk `\*` is quoted from the shell in this
|
||||
example; this lets the command include the files from
|
||||
subdirectories of `Documentation/` directory.
|
||||
example; this lets git, and not the shell, expand the pathnames
|
||||
of files and subdirectories under the `Documentation/` directory.
|
||||
|
||||
git-rm -f git-*.sh::
|
||||
Remove all git-*.sh scripts that are in the index.
|
||||
Because this example lets the shell expand the asterisk
|
||||
(i.e. you are listing the files explicitly), it
|
||||
does not remove `subdir/git-foo.sh`.
|
||||
|
||||
@@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e]
|
||||
git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [<committish>...]
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e] [-w]
|
||||
git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -35,6 +35,12 @@ OPTIONS
|
||||
-e, \--email::
|
||||
Show the email address of each author.
|
||||
|
||||
-w[<width>[,<indent1>[,<indent2>]]]::
|
||||
Linewrap the output by wrapping each line at `width`. The first
|
||||
line of each entry is indented by `indent1` spaces, and the second
|
||||
and subsequent lines are indented by `indent2` spaces. `width`,
|
||||
`indent1`, and `indent2` default to 76, 6 and 9 respectively.
|
||||
|
||||
FILES
|
||||
-----
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ If the config variable `status.relativePaths` is set to false, then all
|
||||
paths shown are relative to the repository root, not to the current
|
||||
directory.
|
||||
|
||||
If `status.submodulesummary` is set to a non zero number or true (identical
|
||||
to -1 or an unlimited number), the submodule summary will be enabled and a
|
||||
summary of commits for modified submodules will be shown (see --summary-limit
|
||||
option of linkgit:git-submodule[1]).
|
||||
|
||||
See Also
|
||||
--------
|
||||
linkgit:gitignore[5]
|
||||
|
||||
@@ -70,7 +70,7 @@ OPTIONS
|
||||
-n, --summary-limit::
|
||||
This option is only valid for the summary command.
|
||||
Limit the summary size (number of commits shown in total).
|
||||
Giving 0 will disable the summary; a negative number means unlimted
|
||||
Giving 0 will disable the summary; a negative number means unlimited
|
||||
(the default). This limit only applies to modified submodules. The
|
||||
size is always limited to 1 for added/deleted/typechanged submodules.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <name> [<head>]
|
||||
'git-tag' -d <name>...
|
||||
'git-tag' [-n [<num>]] -l [<pattern>]
|
||||
'git-tag' [-n[<num>]] -l [<pattern>]
|
||||
'git-tag' -v <name>...
|
||||
|
||||
DESCRIPTION
|
||||
@@ -57,7 +57,7 @@ OPTIONS
|
||||
-v::
|
||||
Verify the gpg signature of the given tag names.
|
||||
|
||||
-n <num>::
|
||||
-n<num>::
|
||||
<num> specifies how many lines from the annotation, if any,
|
||||
are printed when using -l.
|
||||
The default is not to print any annotation lines.
|
||||
@@ -233,14 +233,14 @@ the tag object affects, for example, the ordering of tags in the
|
||||
gitweb interface.
|
||||
|
||||
To set the date used in future tag objects, set the environment
|
||||
variable GIT_AUTHOR_DATE to one or more of the date and time. The
|
||||
variable GIT_COMMITTER_DATE to one or more of the date and time. The
|
||||
date and time can be specified in a number of ways; the most common
|
||||
is "YYYY-MM-DD HH:MM".
|
||||
|
||||
An example follows.
|
||||
|
||||
------------
|
||||
$ GIT_AUTHOR_DATE="2006-10-02 10:31" git tag -s v1.0.1
|
||||
$ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
|
||||
------------
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ git-unpack-objects - Unpack objects from a packed archive
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-unpack-objects' [-n] [-q] [-r] <pack-file
|
||||
'git-unpack-objects' [-n] [-q] [-r] [--strict] <pack-file
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@@ -40,6 +40,9 @@ OPTIONS
|
||||
and make the best effort to recover as many objects as
|
||||
possible.
|
||||
|
||||
--strict::
|
||||
Don't write objects with broken content or links.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -46,8 +46,11 @@ Documentation for older releases are available here:
|
||||
* link:v1.5.5/git.html[documentation for release 1.5.5]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.5.5.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.4.5/git.html[documentation for release 1.5.4.5]
|
||||
|
||||
* release notes for
|
||||
@@ -140,7 +143,8 @@ help ...'.
|
||||
|
||||
--git-dir=<path>::
|
||||
Set the path to the repository. This can also be controlled by
|
||||
setting the GIT_DIR environment variable.
|
||||
setting the GIT_DIR environment variable. It can be an absolute
|
||||
path or relative path to current working directory.
|
||||
|
||||
--work-tree=<path>::
|
||||
Set the path to the working tree. The value will not be
|
||||
@@ -148,7 +152,12 @@ help ...'.
|
||||
a .git directory (i.e. $GIT_DIR is not set).
|
||||
This can also be controlled by setting the GIT_WORK_TREE
|
||||
environment variable and the core.worktree configuration
|
||||
variable.
|
||||
variable. It can be an absolute path or relative path to
|
||||
the directory specified by --git-dir or GIT_DIR.
|
||||
Note: If --git-dir or GIT_DIR are specified but none of
|
||||
--work-tree, GIT_WORK_TREE and core.worktree is specified,
|
||||
the current working directory is regarded as the top directory
|
||||
of your working tree.
|
||||
|
||||
--bare::
|
||||
Treat the repository as a bare repository. If GIT_DIR
|
||||
|
||||
@@ -41,6 +41,12 @@ frequently used options.
|
||||
|
||||
Show all branches.
|
||||
|
||||
--merge::
|
||||
|
||||
After an attempt to merge stops with conflicts, show the commits on
|
||||
the history between two branches (i.e. the HEAD and the MERGE_HEAD)
|
||||
that modify the conflicted files.
|
||||
|
||||
<revs>::
|
||||
|
||||
Limit the revisions to show. This can be either a single revision
|
||||
@@ -74,6 +80,11 @@ gitk --max-count=100 --all \-- Makefile::
|
||||
Show at most 100 changes made to the file 'Makefile'. Instead of only
|
||||
looking for changes in the current branch look in all branches.
|
||||
|
||||
Files
|
||||
-----
|
||||
Gitk creates the .gitk file in your $HOME directory to store preferences
|
||||
such as display options, font, and colors.
|
||||
|
||||
See Also
|
||||
--------
|
||||
'qgit(1)'::
|
||||
|
||||
@@ -276,3 +276,10 @@ probably enable this hook.
|
||||
Both standard output and standard error output are forwarded to
|
||||
`git-send-pack` on the other end, so you can simply `echo` messages
|
||||
for the user.
|
||||
|
||||
pre-auto-gc
|
||||
-----------
|
||||
|
||||
This hook is invoked by `git-gc --auto`. It takes no parameter, and
|
||||
exiting with non-zero status from this script causes the `git-gc --auto`
|
||||
to abort.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
From: Rutger Nijlunsing <rutger@nospam.com>
|
||||
Subject: Setting up a git repository which can be pushed into and pulled from over HTTP.
|
||||
Subject: Setting up a git repository which can be pushed into and pulled from over HTTP(S).
|
||||
Date: Thu, 10 Aug 2006 22:00:26 +0200
|
||||
|
||||
Since Apache is one of those packages people like to compile
|
||||
@@ -40,9 +40,13 @@ What's needed:
|
||||
|
||||
- have permissions to chown a directory
|
||||
|
||||
- have git installed at the server _and_ client
|
||||
- have git installed on the client, and
|
||||
|
||||
In effect, this probably means you're going to be root.
|
||||
- either have git installed on the server or have a webdav client on
|
||||
the client.
|
||||
|
||||
In effect, this means you're going to be root, or that you're using a
|
||||
preconfigured WebDAV server.
|
||||
|
||||
|
||||
Step 1: setup a bare GIT repository
|
||||
@@ -50,9 +54,9 @@ Step 1: setup a bare GIT repository
|
||||
|
||||
At the time of writing, git-http-push cannot remotely create a GIT
|
||||
repository. So we have to do that at the server side with git. Another
|
||||
option would be to generate an empty repository at the client and copy
|
||||
it to the server with WebDAV. But then you're probably the first to
|
||||
try that out :)
|
||||
option is to generate an empty bare repository at the client and copy
|
||||
it to the server with a WebDAV client (which is the only option if Git
|
||||
is not installed on the server).
|
||||
|
||||
Create the directory under the DocumentRoot of the directories served
|
||||
by Apache. As an example we take /usr/local/apache2, but try "grep
|
||||
@@ -169,7 +173,9 @@ On Debian:
|
||||
|
||||
Most tests should pass.
|
||||
|
||||
A command line tool to test WebDAV is cadaver.
|
||||
A command line tool to test WebDAV is cadaver. If you prefer GUIs, for
|
||||
example, konqueror can open WebDAV URLs as "webdav://..." or
|
||||
"webdavs://...".
|
||||
|
||||
If you're into Windows, from XP onwards Internet Explorer supports
|
||||
WebDAV. For this, do Internet Explorer -> Open Location ->
|
||||
@@ -179,8 +185,9 @@ http://<servername>/my-new-repo.git [x] Open as webfolder -> login .
|
||||
Step 3: setup the client
|
||||
------------------------
|
||||
|
||||
Make sure that you have HTTP support, i.e. your git was built with curl.
|
||||
The easiest way to check is to look for the executable 'git-http-push'.
|
||||
Make sure that you have HTTP support, i.e. your git was built with
|
||||
curl (version more recent than 7.10). The command 'git http-push' with
|
||||
no argument should display a usage message.
|
||||
|
||||
Then, add the following to your $HOME/.netrc (you can do without, but will be
|
||||
asked to input your password a _lot_ of times):
|
||||
@@ -197,10 +204,10 @@ instead of the server name.
|
||||
|
||||
To check whether all is OK, do:
|
||||
|
||||
curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/
|
||||
|
||||
...this should give a directory listing in HTML of /var/www/my-new-repo.git .
|
||||
curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD
|
||||
|
||||
...this should give something like 'ref: refs/heads/master', which is
|
||||
the content of the file HEAD on the server.
|
||||
|
||||
Now, add the remote in your existing repository which contains the project
|
||||
you want to export:
|
||||
@@ -225,6 +232,15 @@ want to export) to repository called 'upload', which we previously
|
||||
defined with git-config.
|
||||
|
||||
|
||||
Using a proxy:
|
||||
--------------
|
||||
|
||||
If you have to access the WebDAV server from behind an HTTP(S) proxy,
|
||||
set the variable 'all_proxy' to 'http://proxy-host.com:port', or
|
||||
'http://login-on-proxy:passwd-on-proxy@proxy-host.com:port'. See 'man
|
||||
curl' for details.
|
||||
|
||||
|
||||
Troubleshooting:
|
||||
----------------
|
||||
|
||||
@@ -248,9 +264,14 @@ Reading /usr/local/apache2/logs/error_log is often helpful.
|
||||
|
||||
On Debian: Read /var/log/apache2/error.log instead.
|
||||
|
||||
If you access HTTPS locations, git may fail verifying the SSL
|
||||
certificate (this is return code 60). Setting http.sslVerify=false can
|
||||
help diagnosing the problem, but removes security checks.
|
||||
|
||||
|
||||
Debian References: http://www.debian-administration.org/articles/285
|
||||
|
||||
Authors
|
||||
Johannes Schindelin <Johannes.Schindelin@gmx.de>
|
||||
Rutger Nijlunsing <git@wingding.demon.nl>
|
||||
Matthieu Moy <Matthieu.Moy@imag.fr>
|
||||
|
||||
@@ -123,3 +123,4 @@ The placeholders are:
|
||||
- '%Creset': reset color
|
||||
- '%m': left, right or boundary mark
|
||||
- '%n': newline
|
||||
- '%x00': print a byte from a hex code
|
||||
|
||||
@@ -1548,22 +1548,7 @@ dangling tree b24c2473f1fd3d91352a624795be026d64c8841f
|
||||
|
||||
Dangling objects are not a problem. At worst they may take up a little
|
||||
extra disk space. They can sometimes provide a last-resort method for
|
||||
recovering lost work--see <<dangling-objects>> for details. However, if
|
||||
you wish, you can remove them with linkgit:git-prune[1] or the `--prune`
|
||||
option to linkgit:git-gc[1]:
|
||||
|
||||
-------------------------------------------------
|
||||
$ git gc --prune
|
||||
-------------------------------------------------
|
||||
|
||||
This may be time-consuming. Unlike most other git operations (including
|
||||
git-gc when run without any options), it is not safe to prune while
|
||||
other git operations are in progress in the same repository.
|
||||
|
||||
If linkgit:git-fsck[1] complains about sha1 mismatches or missing
|
||||
objects, you may have a much more serious problem; your best option is
|
||||
probably restoring from backups. See
|
||||
<<recovering-from-repository-corruption>> for a detailed discussion.
|
||||
recovering lost work--see <<dangling-objects>> for details.
|
||||
|
||||
[[recovering-lost-changes]]
|
||||
Recovering lost changes
|
||||
|
||||
4
Makefile
4
Makefile
@@ -189,6 +189,7 @@ ETC_GITCONFIG = $(sysconfdir)/gitconfig
|
||||
|
||||
# default configuration for gitweb
|
||||
GITWEB_CONFIG = gitweb_config.perl
|
||||
GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
|
||||
GITWEB_HOME_LINK_STR = projects
|
||||
GITWEB_SITENAME =
|
||||
GITWEB_PROJECTROOT = /pub/git
|
||||
@@ -364,6 +365,7 @@ LIB_H += refs.h
|
||||
LIB_H += remote.h
|
||||
LIB_H += revision.h
|
||||
LIB_H += run-command.h
|
||||
LIB_H += sha1-lookup.h
|
||||
LIB_H += sideband.h
|
||||
LIB_H += strbuf.h
|
||||
LIB_H += tag.h
|
||||
@@ -444,6 +446,7 @@ LIB_OBJS += run-command.o
|
||||
LIB_OBJS += server-info.o
|
||||
LIB_OBJS += setup.o
|
||||
LIB_OBJS += sha1_file.o
|
||||
LIB_OBJS += sha1-lookup.o
|
||||
LIB_OBJS += sha1_name.o
|
||||
LIB_OBJS += shallow.o
|
||||
LIB_OBJS += sideband.o
|
||||
@@ -1068,6 +1071,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
|
||||
-e 's|++GIT_BINDIR++|$(bindir)|g' \
|
||||
-e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
|
||||
-e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
|
||||
-e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
|
||||
-e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
|
||||
-e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
|
||||
|
||||
@@ -17,6 +17,7 @@ static time_t archive_time;
|
||||
static int tar_umask = 002;
|
||||
static int verbose;
|
||||
static const struct commit *commit;
|
||||
static size_t base_len;
|
||||
|
||||
/* writes out the whole block, but only if it is full */
|
||||
static void write_if_needed(void)
|
||||
@@ -251,8 +252,8 @@ static int write_tar_entry(const unsigned char *sha1,
|
||||
buffer = NULL;
|
||||
size = 0;
|
||||
} else {
|
||||
buffer = sha1_file_to_archive(path.buf, sha1, mode, &type,
|
||||
&size, commit);
|
||||
buffer = sha1_file_to_archive(path.buf + base_len, sha1, mode,
|
||||
&type, &size, commit);
|
||||
if (!buffer)
|
||||
die("cannot read %s", sha1_to_hex(sha1));
|
||||
}
|
||||
@@ -272,6 +273,7 @@ int write_tar_archive(struct archiver_args *args)
|
||||
archive_time = args->time;
|
||||
verbose = args->verbose;
|
||||
commit = args->commit;
|
||||
base_len = args->base ? strlen(args->base) : 0;
|
||||
|
||||
if (args->commit_sha1)
|
||||
write_global_extended_header(args->commit_sha1);
|
||||
|
||||
@@ -13,6 +13,7 @@ static int verbose;
|
||||
static int zip_date;
|
||||
static int zip_time;
|
||||
static const struct commit *commit;
|
||||
static size_t base_len;
|
||||
|
||||
static unsigned char *zip_dir;
|
||||
static unsigned int zip_dir_size;
|
||||
@@ -197,8 +198,8 @@ static int write_zip_entry(const unsigned char *sha1,
|
||||
if (S_ISREG(mode) && zlib_compression_level != 0)
|
||||
method = 8;
|
||||
result = 0;
|
||||
buffer = sha1_file_to_archive(path, sha1, mode, &type, &size,
|
||||
commit);
|
||||
buffer = sha1_file_to_archive(path + base_len, sha1, mode,
|
||||
&type, &size, commit);
|
||||
if (!buffer)
|
||||
die("cannot read %s", sha1_to_hex(sha1));
|
||||
crc = crc32(crc, buffer, size);
|
||||
@@ -321,6 +322,7 @@ int write_zip_archive(struct archiver_args *args)
|
||||
zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
|
||||
verbose = args->verbose;
|
||||
commit = args->commit;
|
||||
base_len = args->base ? strlen(args->base) : 0;
|
||||
|
||||
if (args->base && plen > 0 && args->base[plen - 1] == '/') {
|
||||
char *base = xstrdup(args->base);
|
||||
|
||||
@@ -16,9 +16,9 @@ static void format_subst(const struct commit *commit,
|
||||
const char *b, *c;
|
||||
|
||||
b = memmem(src, len, "$Format:", 8);
|
||||
if (!b || src + len < b + 9)
|
||||
if (!b)
|
||||
break;
|
||||
c = memchr(b + 8, '$', len - 8);
|
||||
c = memchr(b + 8, '$', (src + len) - b - 8);
|
||||
if (!c)
|
||||
break;
|
||||
|
||||
|
||||
4
attr.c
4
attr.c
@@ -546,7 +546,9 @@ static int path_matches(const char *pathname, int pathlen,
|
||||
(baselen && pathname[baselen] != '/') ||
|
||||
strncmp(pathname, base, baselen))
|
||||
return 0;
|
||||
return fnmatch(pattern, pathname + baselen + 1, FNM_PATHNAME) == 0;
|
||||
if (baselen != 0)
|
||||
baselen++;
|
||||
return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
|
||||
}
|
||||
|
||||
static int fill_one(const char *what, struct match_attr *a, int rem)
|
||||
|
||||
@@ -2981,12 +2981,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
|
||||
static int git_apply_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "apply.whitespace")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
apply_default_whitespace = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "apply.whitespace"))
|
||||
return git_config_string(&apply_default_whitespace, var, value);
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
@@ -3121,7 +3117,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||
|
||||
fd = open(arg, O_RDONLY);
|
||||
if (fd < 0)
|
||||
usage(apply_usage);
|
||||
die("can't open patch '%s': %s", arg, strerror(errno));
|
||||
read_stdin = 0;
|
||||
set_default_whitespace_mode(whitespace_option);
|
||||
errs |= apply_patch(fd, arg, inaccurate_eof);
|
||||
|
||||
@@ -504,7 +504,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
OPT__QUIET(&opts.quiet),
|
||||
OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
|
||||
OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
|
||||
OPT_SET_INT( 0 , "track", &opts.track, "track",
|
||||
OPT_SET_INT('t', "track", &opts.track, "track",
|
||||
BRANCH_TRACK_EXPLICIT),
|
||||
OPT_BOOLEAN('f', NULL, &opts.force, "force"),
|
||||
OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
|
||||
|
||||
@@ -95,7 +95,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
|
||||
for (i = 0; i < dir.nr; i++) {
|
||||
struct dir_entry *ent = dir.entries[i];
|
||||
int len, pos, matches;
|
||||
int len, pos;
|
||||
int matches = 0;
|
||||
struct cache_entry *ce;
|
||||
struct stat st;
|
||||
|
||||
@@ -127,18 +128,18 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (pathspec) {
|
||||
memset(seen, 0, argc > 0 ? argc : 1);
|
||||
matches = match_pathspec(pathspec, ent->name, ent->len,
|
||||
matches = match_pathspec(pathspec, ent->name, len,
|
||||
baselen, seen);
|
||||
} else {
|
||||
matches = 0;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
strbuf_addstr(&directory, ent->name);
|
||||
qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
|
||||
if (show_only && (remove_directories || matches)) {
|
||||
if (show_only && (remove_directories ||
|
||||
(matches == MATCHED_EXACTLY))) {
|
||||
printf("Would remove %s\n", qname);
|
||||
} else if (remove_directories || matches) {
|
||||
} else if (remove_directories ||
|
||||
(matches == MATCHED_EXACTLY)) {
|
||||
if (!quiet)
|
||||
printf("Removing %s\n", qname);
|
||||
if (remove_dir_recursively(&directory, 0) != 0) {
|
||||
|
||||
@@ -90,7 +90,7 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
|
||||
OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
|
||||
OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
|
||||
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"),
|
||||
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
|
||||
OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"),
|
||||
OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
|
||||
|
||||
@@ -98,7 +98,7 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
|
||||
OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
|
||||
OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
|
||||
OPT_BOOLEAN('o', "only", &only, ""),
|
||||
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
|
||||
OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
|
||||
OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
|
||||
OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"),
|
||||
@@ -745,10 +745,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
die("No paths with --include/--only does not make sense.");
|
||||
if (argc == 0 && only && amend)
|
||||
only_include_assumed = "Clever... amending the last one with dirty index.";
|
||||
if (argc > 0 && !also && !only) {
|
||||
if (argc > 0 && !also && !only)
|
||||
only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
|
||||
also = 0;
|
||||
}
|
||||
if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
|
||||
cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
|
||||
else if (!strcmp(cleanup_arg, "verbatim"))
|
||||
@@ -810,7 +808,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
|
||||
rev.verbose_header = 1;
|
||||
rev.show_root_diff = 1;
|
||||
rev.commit_format = get_commit_format("format:%h: %s");
|
||||
get_commit_format("format:%h: %s", &rev);
|
||||
rev.always_show_header = 0;
|
||||
rev.diffopt.detect_rename = 1;
|
||||
rev.diffopt.rename_limit = 100;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "color.h"
|
||||
|
||||
static const char git_config_set_usage[] =
|
||||
"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
|
||||
"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
|
||||
|
||||
static char *key;
|
||||
static regex_t *key_regexp;
|
||||
@@ -16,7 +16,7 @@ static int seen;
|
||||
static char delim = '=';
|
||||
static char key_delim = ' ';
|
||||
static char term = '\n';
|
||||
static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
|
||||
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_)
|
||||
{
|
||||
@@ -53,6 +53,14 @@ static int show_config(const char* key_, const char* value_)
|
||||
sprintf(value, "%d", git_config_int(key_, value_?value_:""));
|
||||
else if (type == T_BOOL)
|
||||
vptr = git_config_bool(key_, value_) ? "true" : "false";
|
||||
else if (type == T_BOOL_OR_INT) {
|
||||
int is_bool, v;
|
||||
v = git_config_bool_or_int(key_, value_, &is_bool);
|
||||
if (is_bool)
|
||||
vptr = v ? "true" : "false";
|
||||
else
|
||||
sprintf(value, "%d", v);
|
||||
}
|
||||
else
|
||||
vptr = value_?value_:"";
|
||||
seen++;
|
||||
@@ -157,6 +165,14 @@ char *normalize_value(const char *key, const char *value)
|
||||
else if (type == T_BOOL)
|
||||
sprintf(normalized, "%s",
|
||||
git_config_bool(key, value) ? "true" : "false");
|
||||
else if (type == T_BOOL_OR_INT) {
|
||||
int is_bool, v;
|
||||
v = git_config_bool_or_int(key, value, &is_bool);
|
||||
if (!is_bool)
|
||||
sprintf(normalized, "%d", v);
|
||||
else
|
||||
sprintf(normalized, "%s", v ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
@@ -224,6 +240,10 @@ static int git_get_colorbool_config(const char *var, const char *value)
|
||||
get_diff_color_found =
|
||||
git_config_colorbool(var, value, stdout_is_tty);
|
||||
}
|
||||
if (!strcmp(var, "color.ui")) {
|
||||
git_use_color_default = git_config_colorbool(var, value, stdout_is_tty);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -251,7 +271,7 @@ static int get_colorbool(int argc, const char **argv)
|
||||
if (!strcmp(get_color_slot, "color.diff"))
|
||||
get_colorbool_found = get_diff_color_found;
|
||||
if (get_colorbool_found < 0)
|
||||
get_colorbool_found = 0;
|
||||
get_colorbool_found = git_use_color_default;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
@@ -273,6 +293,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
||||
type = T_INT;
|
||||
else if (!strcmp(argv[1], "--bool"))
|
||||
type = T_BOOL;
|
||||
else if (!strcmp(argv[1], "--bool-or-int"))
|
||||
type = T_BOOL_OR_INT;
|
||||
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
|
||||
if (argc != 2)
|
||||
usage(git_config_set_usage);
|
||||
|
||||
@@ -117,15 +117,15 @@ static const unsigned char* get_rev(void)
|
||||
|
||||
while (commit == NULL) {
|
||||
unsigned int mark;
|
||||
struct commit_list *parents = NULL;
|
||||
struct commit_list *parents;
|
||||
|
||||
if (rev_list == NULL || non_common_revs == 0)
|
||||
return NULL;
|
||||
|
||||
commit = rev_list->item;
|
||||
if (!(commit->object.parsed))
|
||||
if (!parse_commit(commit))
|
||||
parents = commit->parents;
|
||||
if (!commit->object.parsed)
|
||||
parse_commit(commit);
|
||||
parents = commit->parents;
|
||||
|
||||
commit->object.flags |= POPPED;
|
||||
if (!(commit->object.flags & COMMON))
|
||||
|
||||
@@ -215,13 +215,6 @@ static int update_local_ref(struct ref *ref,
|
||||
if (type < 0)
|
||||
die("object %s not found", sha1_to_hex(ref->new_sha1));
|
||||
|
||||
if (!*ref->name) {
|
||||
/* Not storing */
|
||||
if (verbose)
|
||||
sprintf(display, "* branch %s -> FETCH_HEAD", remote);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
|
||||
if (verbose)
|
||||
sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH,
|
||||
@@ -365,16 +358,21 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
|
||||
rm->merge ? "" : "not-for-merge",
|
||||
note);
|
||||
|
||||
if (ref) {
|
||||
if (ref)
|
||||
update_local_ref(ref, what, verbose, note);
|
||||
if (*note) {
|
||||
if (!shown_url) {
|
||||
fprintf(stderr, "From %.*s\n",
|
||||
url_len, url);
|
||||
shown_url = 1;
|
||||
}
|
||||
fprintf(stderr, " %s\n", note);
|
||||
else if (verbose)
|
||||
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
|
||||
SUMMARY_WIDTH, *kind ? kind : "branch",
|
||||
REFCOL_WIDTH, *what ? what : "HEAD");
|
||||
else
|
||||
*note = '\0';
|
||||
if (*note) {
|
||||
if (!shown_url) {
|
||||
fprintf(stderr, "From %.*s\n",
|
||||
url_len, url);
|
||||
shown_url = 1;
|
||||
}
|
||||
fprintf(stderr, " %s\n", note);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
@@ -579,8 +577,6 @@ static int do_fetch(struct transport *transport,
|
||||
free_refs(ref_map);
|
||||
}
|
||||
|
||||
transport_disconnect(transport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -601,6 +597,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
int i;
|
||||
static const char **refs = NULL;
|
||||
int ref_nr = 0;
|
||||
int exit_code;
|
||||
|
||||
/* Record the command line for the reflog */
|
||||
strbuf_addstr(&default_rla, "fetch");
|
||||
@@ -654,6 +651,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
|
||||
signal(SIGINT, unlock_pack_on_signal);
|
||||
atexit(unlock_pack);
|
||||
return do_fetch(transport,
|
||||
exit_code = do_fetch(transport,
|
||||
parse_fetch_refspec(ref_nr, refs), ref_nr);
|
||||
transport_disconnect(transport);
|
||||
transport = NULL;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
@@ -201,6 +201,15 @@ static void shortlog(const char *name, unsigned char *sha1,
|
||||
continue;
|
||||
|
||||
bol = strstr(commit->buffer, "\n\n");
|
||||
if (bol) {
|
||||
unsigned char c;
|
||||
do {
|
||||
c = *++bol;
|
||||
} while (isspace(c));
|
||||
if (!c)
|
||||
bol = NULL;
|
||||
}
|
||||
|
||||
if (!bol) {
|
||||
append_to_list(&subjects, xstrdup(sha1_to_hex(
|
||||
commit->object.sha1)),
|
||||
@@ -208,7 +217,6 @@ static void shortlog(const char *name, unsigned char *sha1,
|
||||
continue;
|
||||
}
|
||||
|
||||
bol += 2;
|
||||
eol = strchr(bol, '\n');
|
||||
if (eol) {
|
||||
oneline = xmemdupz(bol, eol - bol);
|
||||
|
||||
31
builtin-gc.c
31
builtin-gc.c
@@ -157,6 +157,34 @@ static int too_many_packs(void)
|
||||
return gc_auto_pack_limit <= cnt;
|
||||
}
|
||||
|
||||
static int run_hook(void)
|
||||
{
|
||||
const char *argv[2];
|
||||
struct child_process hook;
|
||||
int ret;
|
||||
|
||||
argv[0] = git_path("hooks/pre-auto-gc");
|
||||
argv[1] = NULL;
|
||||
|
||||
if (access(argv[0], X_OK) < 0)
|
||||
return 0;
|
||||
|
||||
memset(&hook, 0, sizeof(hook));
|
||||
hook.argv = argv;
|
||||
hook.no_stdin = 1;
|
||||
hook.stdout_to_stderr = 1;
|
||||
|
||||
ret = start_command(&hook);
|
||||
if (ret) {
|
||||
warning("Could not spawn %s", argv[0]);
|
||||
return ret;
|
||||
}
|
||||
ret = finish_command(&hook);
|
||||
if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
|
||||
warning("%s exited due to uncaught signal", argv[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int need_to_gc(void)
|
||||
{
|
||||
/*
|
||||
@@ -176,6 +204,9 @@ static int need_to_gc(void)
|
||||
append_option(argv_repack, "-A", MAX_ADD);
|
||||
else if (!too_many_loose_objects())
|
||||
return 0;
|
||||
|
||||
if (run_hook())
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -400,9 +400,16 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
char buf[10];
|
||||
/* We do not spell "group" and such, so that
|
||||
* the configuration can be read by older version
|
||||
* of git.
|
||||
* of git. Note, we use octal numbers for new share modes,
|
||||
* and compatibility values for PERM_GROUP and
|
||||
* PERM_EVERYBODY.
|
||||
*/
|
||||
sprintf(buf, "%d", shared_repository);
|
||||
if (shared_repository == PERM_GROUP)
|
||||
sprintf(buf, "%d", OLD_PERM_GROUP);
|
||||
else if (shared_repository == PERM_EVERYBODY)
|
||||
sprintf(buf, "%d", OLD_PERM_EVERYBODY);
|
||||
else
|
||||
sprintf(buf, "0%o", shared_repository);
|
||||
git_config_set("core.sharedrepository", buf);
|
||||
git_config_set("receive.denyNonFastforwards", "true");
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
if (fmt_pretty)
|
||||
rev->commit_format = get_commit_format(fmt_pretty);
|
||||
get_commit_format(fmt_pretty, rev);
|
||||
rev->verbose_header = 1;
|
||||
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
|
||||
rev->show_root_diff = default_show_root;
|
||||
@@ -400,6 +400,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
|
||||
* allow us to set a different default.
|
||||
*/
|
||||
rev.commit_format = CMIT_FMT_ONELINE;
|
||||
rev.use_terminator = 1;
|
||||
rev.always_show_header = 1;
|
||||
|
||||
/*
|
||||
|
||||
@@ -19,6 +19,8 @@ static const char * const builtin_remote_usage[] = {
|
||||
|
||||
static int verbose;
|
||||
|
||||
static int show_all(void);
|
||||
|
||||
static inline int postfixcmp(const char *string, const char *postfix)
|
||||
{
|
||||
int len1 = strlen(string), len2 = strlen(postfix);
|
||||
@@ -88,19 +90,24 @@ static int add(int argc, const char **argv)
|
||||
strbuf_init(&buf, 0);
|
||||
strbuf_init(&buf2, 0);
|
||||
|
||||
strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name);
|
||||
if (!valid_fetch_refspec(buf2.buf))
|
||||
die("'%s' is not a valid remote name", name);
|
||||
|
||||
strbuf_addf(&buf, "remote.%s.url", name);
|
||||
if (git_config_set(buf.buf, url))
|
||||
return 1;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "remote.%s.fetch", name);
|
||||
|
||||
if (track.nr == 0)
|
||||
path_list_append("*", &track);
|
||||
for (i = 0; i < track.nr; i++) {
|
||||
struct path_list_item *item = track.items + i;
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "remote.%s.fetch", name);
|
||||
|
||||
strbuf_reset(&buf2);
|
||||
strbuf_addch(&buf2, '+');
|
||||
if (mirror)
|
||||
strbuf_addf(&buf2, "refs/%s:refs/%s",
|
||||
item->path, item->path);
|
||||
@@ -380,8 +387,11 @@ static int show_or_prune(int argc, const char **argv, int prune)
|
||||
|
||||
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
|
||||
|
||||
if (argc < 1)
|
||||
if (argc < 1) {
|
||||
if (!prune)
|
||||
return show_all();
|
||||
usage_with_options(builtin_remote_usage, options);
|
||||
}
|
||||
|
||||
memset(&states, 0, sizeof(states));
|
||||
for (; argc; argc--, argv++) {
|
||||
|
||||
@@ -365,9 +365,17 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void die_no_single_rev(int quiet)
|
||||
{
|
||||
if (quiet)
|
||||
exit(1);
|
||||
else
|
||||
die("Needed a single revision");
|
||||
}
|
||||
|
||||
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, as_is = 0, verify = 0;
|
||||
int i, as_is = 0, verify = 0, quiet = 0;
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (argc > 1 && !strcmp("--parseopt", argv[1]))
|
||||
@@ -432,6 +440,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
verify = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
|
||||
quiet = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--short") ||
|
||||
!prefixcmp(arg, "--short=")) {
|
||||
filter &= ~(DO_FLAGS|DO_NOREV);
|
||||
@@ -549,7 +561,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (show_flag(arg) && verify)
|
||||
die("Needed a single revision");
|
||||
die_no_single_rev(quiet);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -564,15 +576,15 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
show_rev(REVERSED, sha1, arg+1);
|
||||
continue;
|
||||
}
|
||||
if (verify)
|
||||
die_no_single_rev(quiet);
|
||||
as_is = 1;
|
||||
if (!show_file(arg))
|
||||
continue;
|
||||
if (verify)
|
||||
die("Needed a single revision");
|
||||
verify_filename(prefix, arg);
|
||||
}
|
||||
show_default();
|
||||
if (verify && revs_count != 1)
|
||||
die("Needed a single revision");
|
||||
die_no_single_rev(quiet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "shortlog.h"
|
||||
|
||||
static const char shortlog_usage[] =
|
||||
"git-shortlog [-n] [-s] [-e] [<commit-id>... ]";
|
||||
"git-shortlog [-n] [-s] [-e] [-w] [<commit-id>... ]";
|
||||
|
||||
static int compare_by_number(const void *a1, const void *a2)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
static const char * const git_tag_usage[] = {
|
||||
"git-tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
|
||||
"git-tag -d <tagname>...",
|
||||
"git-tag -l [-n [<num>]] [<pattern>]",
|
||||
"git-tag -l [-n[<num>]] [<pattern>]",
|
||||
"git-tag -v <tagname>...",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
#include "tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "progress.h"
|
||||
#include "decorate.h"
|
||||
#include "fsck.h"
|
||||
|
||||
static int dry_run, quiet, recover, has_errors;
|
||||
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
|
||||
static int dry_run, quiet, recover, has_errors, strict;
|
||||
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
|
||||
|
||||
/* We always read in 4kB chunks. */
|
||||
static unsigned char buffer[4096];
|
||||
@@ -19,6 +21,11 @@ static unsigned int offset, len;
|
||||
static off_t consumed_bytes;
|
||||
static SHA_CTX ctx;
|
||||
|
||||
/*
|
||||
* When running under --strict mode, objects whose reachability are
|
||||
* suspect are kept in core without getting written in the object
|
||||
* store.
|
||||
*/
|
||||
struct obj_buffer {
|
||||
char *buffer;
|
||||
unsigned long size;
|
||||
@@ -31,6 +38,16 @@ static struct obj_buffer *lookup_object_buffer(struct object *base)
|
||||
return lookup_decoration(&obj_decorate, base);
|
||||
}
|
||||
|
||||
static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
|
||||
{
|
||||
struct obj_buffer *obj;
|
||||
obj = xcalloc(1, sizeof(struct obj_buffer));
|
||||
obj->buffer = buffer;
|
||||
obj->size = size;
|
||||
if (add_decoration(&obj_decorate, object, obj))
|
||||
die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure at least "min" bytes are available in the buffer, and
|
||||
* return the pointer to the buffer.
|
||||
@@ -134,19 +151,110 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
|
||||
struct obj_info {
|
||||
off_t offset;
|
||||
unsigned char sha1[20];
|
||||
struct object *obj;
|
||||
};
|
||||
|
||||
#define FLAG_OPEN (1u<<20)
|
||||
#define FLAG_WRITTEN (1u<<21)
|
||||
|
||||
static struct obj_info *obj_list;
|
||||
unsigned nr_objects;
|
||||
|
||||
/*
|
||||
* Called only from check_object() after it verified this object
|
||||
* is Ok.
|
||||
*/
|
||||
static void write_cached_object(struct object *obj)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
||||
if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
|
||||
die("failed to write object %s", sha1_to_hex(obj->sha1));
|
||||
obj->flags |= FLAG_WRITTEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* At the very end of the processing, write_rest() scans the objects
|
||||
* that have reachability requirements and calls this function.
|
||||
* Verify its reachability and validity recursively and write it out.
|
||||
*/
|
||||
static int check_object(struct object *obj, int type, void *data)
|
||||
{
|
||||
if (!obj)
|
||||
return 0;
|
||||
|
||||
if (obj->flags & FLAG_WRITTEN)
|
||||
return 1;
|
||||
|
||||
if (type != OBJ_ANY && obj->type != type)
|
||||
die("object type mismatch");
|
||||
|
||||
if (!(obj->flags & FLAG_OPEN)) {
|
||||
unsigned long size;
|
||||
int type = sha1_object_info(obj->sha1, &size);
|
||||
if (type != obj->type || type <= 0)
|
||||
die("object of unexpected type");
|
||||
obj->flags |= FLAG_WRITTEN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fsck_object(obj, 1, fsck_error_function))
|
||||
die("Error in object");
|
||||
if (!fsck_walk(obj, check_object, 0))
|
||||
die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
|
||||
write_cached_object(obj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void write_rest(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < nr_objects; i++)
|
||||
check_object(obj_list[i].obj, OBJ_ANY, 0);
|
||||
}
|
||||
|
||||
static void added_object(unsigned nr, enum object_type type,
|
||||
void *data, unsigned long size);
|
||||
|
||||
/*
|
||||
* Write out nr-th object from the list, now we know the contents
|
||||
* of it. Under --strict, this buffers structured objects in-core,
|
||||
* to be checked at the end.
|
||||
*/
|
||||
static void write_object(unsigned nr, enum object_type type,
|
||||
void *buf, unsigned long size)
|
||||
{
|
||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||
die("failed to write object");
|
||||
added_object(nr, type, buf, size);
|
||||
if (!strict) {
|
||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||
die("failed to write object");
|
||||
added_object(nr, type, buf, size);
|
||||
free(buf);
|
||||
obj_list[nr].obj = NULL;
|
||||
} else if (type == OBJ_BLOB) {
|
||||
struct blob *blob;
|
||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||
die("failed to write object");
|
||||
added_object(nr, type, buf, size);
|
||||
free(buf);
|
||||
|
||||
blob = lookup_blob(obj_list[nr].sha1);
|
||||
if (blob)
|
||||
blob->object.flags |= FLAG_WRITTEN;
|
||||
else
|
||||
die("invalid blob object");
|
||||
obj_list[nr].obj = NULL;
|
||||
} else {
|
||||
struct object *obj;
|
||||
int eaten;
|
||||
hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
|
||||
added_object(nr, type, buf, size);
|
||||
obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
|
||||
if (!obj)
|
||||
die("invalid %s", typename(type));
|
||||
add_object_buffer(obj, buf, size);
|
||||
obj->flags |= FLAG_OPEN;
|
||||
obj_list[nr].obj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_delta(unsigned nr, enum object_type type,
|
||||
@@ -163,9 +271,12 @@ static void resolve_delta(unsigned nr, enum object_type type,
|
||||
die("failed to apply delta");
|
||||
free(delta);
|
||||
write_object(nr, type, result, result_size);
|
||||
free(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* We now know the contents of an object (which is nr-th in the pack);
|
||||
* resolve all the deltified objects that are based on it.
|
||||
*/
|
||||
static void added_object(unsigned nr, enum object_type type,
|
||||
void *data, unsigned long size)
|
||||
{
|
||||
@@ -193,7 +304,24 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
|
||||
|
||||
if (!dry_run && buf)
|
||||
write_object(nr, type, buf, size);
|
||||
free(buf);
|
||||
else
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static int resolve_against_held(unsigned nr, const unsigned char *base,
|
||||
void *delta_data, unsigned long delta_size)
|
||||
{
|
||||
struct object *obj;
|
||||
struct obj_buffer *obj_buffer;
|
||||
obj = lookup_object(base);
|
||||
if (!obj)
|
||||
return 0;
|
||||
obj_buffer = lookup_object_buffer(obj);
|
||||
if (!obj_buffer)
|
||||
return 0;
|
||||
resolve_delta(nr, obj->type, obj_buffer->buffer,
|
||||
obj_buffer->size, delta_data, delta_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
@@ -202,7 +330,6 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
void *delta_data, *base;
|
||||
unsigned long base_size;
|
||||
unsigned char base_sha1[20];
|
||||
struct object *obj;
|
||||
|
||||
if (type == OBJ_REF_DELTA) {
|
||||
hashcpy(base_sha1, fill(20));
|
||||
@@ -212,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
free(delta_data);
|
||||
return;
|
||||
}
|
||||
if (!has_sha1_file(base_sha1)) {
|
||||
if (has_sha1_file(base_sha1))
|
||||
; /* Ok we have this one */
|
||||
else if (resolve_against_held(nr, base_sha1,
|
||||
delta_data, delta_size))
|
||||
return; /* we are done */
|
||||
else {
|
||||
/* cannot resolve yet --- queue it */
|
||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
|
||||
return;
|
||||
@@ -258,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
}
|
||||
}
|
||||
if (!base_found) {
|
||||
/* The delta base object is itself a delta that
|
||||
has not been resolved yet. */
|
||||
/*
|
||||
* The delta base object is itself a delta that
|
||||
* has not been resolved yet.
|
||||
*/
|
||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
obj = lookup_object(base_sha1);
|
||||
if (obj) {
|
||||
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
||||
if (obj_buf) {
|
||||
resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
|
||||
return;
|
||||
|
||||
base = read_sha1_file(base_sha1, &type, &base_size);
|
||||
if (!base) {
|
||||
@@ -336,7 +465,8 @@ static void unpack_all(void)
|
||||
int i;
|
||||
struct progress *progress = NULL;
|
||||
struct pack_header *hdr = fill(sizeof(struct pack_header));
|
||||
unsigned nr_objects = ntohl(hdr->hdr_entries);
|
||||
|
||||
nr_objects = ntohl(hdr->hdr_entries);
|
||||
|
||||
if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
|
||||
die("bad pack file");
|
||||
@@ -347,6 +477,7 @@ static void unpack_all(void)
|
||||
if (!quiet)
|
||||
progress = start_progress("Unpacking objects", nr_objects);
|
||||
obj_list = xmalloc(nr_objects * sizeof(*obj_list));
|
||||
memset(obj_list, 0, nr_objects * sizeof(*obj_list));
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
unpack_one(i);
|
||||
display_progress(progress, i + 1);
|
||||
@@ -382,6 +513,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
||||
recover = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--strict")) {
|
||||
strict = 1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--pack_header=")) {
|
||||
struct pack_header *hdr;
|
||||
char *c;
|
||||
@@ -407,6 +542,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
||||
unpack_all();
|
||||
SHA1_Update(&ctx, buffer, offset);
|
||||
SHA1_Final(sha1, &ctx);
|
||||
if (strict)
|
||||
write_rest();
|
||||
if (hashcmp(fill(20), sha1))
|
||||
die("final sha1 did not match");
|
||||
use(20);
|
||||
|
||||
@@ -341,8 +341,11 @@ static int update_one(struct cache_tree *it,
|
||||
|
||||
if (dryrun)
|
||||
hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
|
||||
else
|
||||
write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
|
||||
else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) {
|
||||
strbuf_release(&buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strbuf_release(&buffer);
|
||||
it->entry_count = i;
|
||||
#if DEBUG
|
||||
|
||||
21
cache.h
21
cache.h
@@ -474,10 +474,20 @@ static inline void hashclr(unsigned char *hash)
|
||||
|
||||
int git_mkstemp(char *path, size_t n, const char *template);
|
||||
|
||||
/*
|
||||
* NOTE NOTE NOTE!!
|
||||
*
|
||||
* PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
|
||||
* not be changed. Old repositories have core.sharedrepository written in
|
||||
* numeric format, and therefore these values are preserved for compatibility
|
||||
* reasons.
|
||||
*/
|
||||
enum sharedrepo {
|
||||
PERM_UMASK = 0,
|
||||
PERM_GROUP,
|
||||
PERM_EVERYBODY
|
||||
PERM_UMASK = 0,
|
||||
OLD_PERM_GROUP = 1,
|
||||
OLD_PERM_EVERYBODY = 2,
|
||||
PERM_GROUP = 0660,
|
||||
PERM_EVERYBODY = 0664,
|
||||
};
|
||||
int git_config_perm(const char *var, const char *value);
|
||||
int adjust_shared_perm(const char *path);
|
||||
@@ -692,6 +702,7 @@ extern int git_parse_long(const char *, long *);
|
||||
extern int git_parse_ulong(const char *, unsigned long *);
|
||||
extern int git_config_int(const char *, const char *);
|
||||
extern unsigned long git_config_ulong(const char *, const char *);
|
||||
extern int git_config_bool_or_int(const char *, const char *, int *);
|
||||
extern int git_config_bool(const char *, const char *);
|
||||
extern int git_config_string(const char **, const char *, const char *);
|
||||
extern int git_config_set(const char *, const char *);
|
||||
@@ -715,8 +726,8 @@ extern const char *git_log_output_encoding;
|
||||
extern void maybe_flush_or_die(FILE *, const char *);
|
||||
extern int copy_fd(int ifd, int ofd);
|
||||
extern int copy_file(const char *dst, const char *src, int mode);
|
||||
extern int read_in_full(int fd, void *buf, size_t count);
|
||||
extern int write_in_full(int fd, const void *buf, size_t count);
|
||||
extern ssize_t read_in_full(int fd, void *buf, size_t count);
|
||||
extern ssize_t write_in_full(int fd, const void *buf, size_t count);
|
||||
extern void write_or_die(int fd, const void *buf, size_t count);
|
||||
extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
|
||||
extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
|
||||
|
||||
@@ -718,9 +718,9 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
result = xmalloc(len + 1);
|
||||
while (sz < len) {
|
||||
ssize_t done = xread(fd, result+sz, len-sz);
|
||||
if (done == 0)
|
||||
break;
|
||||
if (done < 0)
|
||||
if (done == 0 && sz != len)
|
||||
die("early EOF '%s'", elem->path);
|
||||
else if (done < 0)
|
||||
die("read error '%s'", elem->path);
|
||||
sz += done;
|
||||
}
|
||||
|
||||
3
commit.h
3
commit.h
@@ -63,7 +63,8 @@ enum cmit_fmt {
|
||||
};
|
||||
|
||||
extern int non_ascii(int);
|
||||
extern enum cmit_fmt get_commit_format(const char *arg);
|
||||
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
|
||||
extern void get_commit_format(const char *arg, struct rev_info *);
|
||||
extern void format_commit_message(const struct commit *commit,
|
||||
const void *format, struct strbuf *sb);
|
||||
extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
|
||||
|
||||
12
config.c
12
config.c
@@ -303,8 +303,9 @@ unsigned long git_config_ulong(const char *name, const char *value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_bool(const char *name, const char *value)
|
||||
int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
|
||||
{
|
||||
*is_bool = 1;
|
||||
if (!value)
|
||||
return 1;
|
||||
if (!*value)
|
||||
@@ -313,7 +314,14 @@ int git_config_bool(const char *name, const char *value)
|
||||
return 1;
|
||||
if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
|
||||
return 0;
|
||||
return git_config_int(name, value) != 0;
|
||||
*is_bool = 0;
|
||||
return git_config_int(name, value);
|
||||
}
|
||||
|
||||
int git_config_bool(const char *name, const char *value)
|
||||
{
|
||||
int discard;
|
||||
return !!git_config_bool_or_int(name, value, &discard);
|
||||
}
|
||||
|
||||
int git_config_string(const char **dest, const char *var, const char *value)
|
||||
|
||||
@@ -152,7 +152,7 @@ __git_heads ()
|
||||
done
|
||||
return
|
||||
fi
|
||||
for i in $(git-ls-remote "$1" 2>/dev/null); do
|
||||
for i in $(git ls-remote "$1" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
y,*) is_hash=n ;;
|
||||
n,*^{}) is_hash=y ;;
|
||||
@@ -173,7 +173,7 @@ __git_tags ()
|
||||
done
|
||||
return
|
||||
fi
|
||||
for i in $(git-ls-remote "$1" 2>/dev/null); do
|
||||
for i in $(git ls-remote "$1" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
y,*) is_hash=n ;;
|
||||
n,*^{}) is_hash=y ;;
|
||||
@@ -200,7 +200,7 @@ __git_refs ()
|
||||
done
|
||||
return
|
||||
fi
|
||||
for i in $(git-ls-remote "$dir" 2>/dev/null); do
|
||||
for i in $(git ls-remote "$dir" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
y,*) is_hash=n ;;
|
||||
n,*^{}) is_hash=y ;;
|
||||
@@ -223,7 +223,7 @@ __git_refs2 ()
|
||||
__git_refs_remotes ()
|
||||
{
|
||||
local cmd i is_hash=y
|
||||
for i in $(git-ls-remote "$1" 2>/dev/null); do
|
||||
for i in $(git ls-remote "$1" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
n,refs/heads/*)
|
||||
is_hash=y
|
||||
@@ -641,6 +641,7 @@ _git_diff ()
|
||||
--ignore-all-space --exit-code --quiet --ext-diff
|
||||
--no-ext-diff
|
||||
--no-prefix --src-prefix= --dst-prefix=
|
||||
--base --ours --theirs
|
||||
"
|
||||
return
|
||||
;;
|
||||
@@ -1052,6 +1053,7 @@ _git_remote ()
|
||||
local subcommands="add rm show prune update"
|
||||
local subcommand="$(__git_find_subcommand "$subcommands")"
|
||||
if [ -z "$subcommand" ]; then
|
||||
__gitcomp "$subcommands"
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -1344,9 +1346,14 @@ _git ()
|
||||
_gitk ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
local g="$(git rev-parse --git-dir 2>/dev/null)"
|
||||
local merge=""
|
||||
if [ -f $g/MERGE_HEAD ]; then
|
||||
merge="--merge"
|
||||
fi
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "--not --all"
|
||||
__gitcomp "--not --all $merge"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -232,10 +232,8 @@ and returns the process output as a string, or nil if the git failed."
|
||||
|
||||
(defun git-run-command-region (buffer start end env &rest args)
|
||||
"Run a git command with specified buffer region as input."
|
||||
(unless (eq 0 (if env
|
||||
(git-run-process-region
|
||||
buffer start end "env"
|
||||
(append (git-get-env-strings env) (list "git") args))
|
||||
(unless (eq 0 (let ((process-environment (append (git-get-env-strings env)
|
||||
process-environment)))
|
||||
(git-run-process-region
|
||||
buffer start end "git" args)))
|
||||
(error "Failed to run \"git %s\":\n%s" (mapconcat (lambda (x) x) args " ") (buffer-string))))
|
||||
@@ -250,9 +248,8 @@ and returns the process output as a string, or nil if the git failed."
|
||||
(erase-buffer)
|
||||
(cd dir)
|
||||
(setq status
|
||||
(if env
|
||||
(apply #'call-process "env" nil (list buffer t) nil
|
||||
(append (git-get-env-strings env) (list hook-name) args))
|
||||
(let ((process-environment (append (git-get-env-strings env)
|
||||
process-environment)))
|
||||
(apply #'call-process hook-name nil (list buffer t) nil args))))
|
||||
(display-message-or-buffer buffer)
|
||||
(eq 0 status)))))
|
||||
|
||||
@@ -202,11 +202,12 @@ generate_email_header()
|
||||
|
||||
generate_email_footer()
|
||||
{
|
||||
SPACE=" "
|
||||
cat <<-EOF
|
||||
|
||||
|
||||
hooks/post-receive
|
||||
--
|
||||
--${SPACE}
|
||||
$projectdesc
|
||||
EOF
|
||||
}
|
||||
|
||||
36
contrib/hooks/pre-auto-gc-battery
Normal file
36
contrib/hooks/pre-auto-gc-battery
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify if you are on battery, in case you
|
||||
# are running Linux. Called by git-gc --auto with no arguments. The hook
|
||||
# should exit with non-zero status after issuing an appropriate message
|
||||
# if it wants to stop the auto repacking.
|
||||
#
|
||||
# This hook is stored in the contrib/hooks directory. Your distribution
|
||||
# may have put this somewhere else. If you want to use this hook, you
|
||||
# should make this script executable then link to it in the repository
|
||||
# you would like to use it in.
|
||||
#
|
||||
# For example, if the hook is stored in
|
||||
# /usr/share/git-core/contrib/hooks/pre-auto-gc-battery:
|
||||
#
|
||||
# chmod a+x pre-auto-gc-battery
|
||||
# cd /path/to/your/repository.git
|
||||
# ln -sf /usr/share/git-core/contrib/hooks/pre-auto-gc-battery \
|
||||
# hooks/pre-auto-gc
|
||||
|
||||
if test -x /sbin/on_ac_power && /sbin/on_ac_power
|
||||
then
|
||||
exit 0
|
||||
elif test "$(cat /sys/class/power_supply/AC/online 2>/dev/null)" = 1
|
||||
then
|
||||
exit 0
|
||||
elif grep -q 'on-line' /proc/acpi/ac_adapter/AC/state 2>/dev/null
|
||||
then
|
||||
exit 0
|
||||
elif grep -q '0x01$' /proc/apm 2>/dev/null
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Auto packing deferred; not on AC"
|
||||
exit 1
|
||||
8
copy.c
8
copy.c
@@ -9,8 +9,7 @@ int copy_fd(int ifd, int ofd)
|
||||
if (!len)
|
||||
break;
|
||||
if (len < 0) {
|
||||
int read_error;
|
||||
read_error = errno;
|
||||
int read_error = errno;
|
||||
close(ifd);
|
||||
return error("copy-fd: read returned %s",
|
||||
strerror(read_error));
|
||||
@@ -25,9 +24,10 @@ int copy_fd(int ifd, int ofd)
|
||||
close(ifd);
|
||||
return error("copy-fd: write returned 0");
|
||||
} else {
|
||||
int write_error = errno;
|
||||
close(ifd);
|
||||
return error("copy-fd: write returned %s",
|
||||
strerror(errno));
|
||||
strerror(write_error));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ int copy_file(const char *dst, const char *src, int mode)
|
||||
}
|
||||
status = copy_fd(fdi, fdo);
|
||||
if (close(fdo) != 0)
|
||||
return error("%s: write error: %s", dst, strerror(errno));
|
||||
return error("%s: close error: %s", dst, strerror(errno));
|
||||
|
||||
if (!status && adjust_shared_perm(dst))
|
||||
return -1;
|
||||
|
||||
@@ -264,6 +264,9 @@ int setup_diff_no_index(struct rev_info *revs,
|
||||
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
|
||||
break;
|
||||
}
|
||||
if (nongit && argc != i + 2)
|
||||
die("git diff [--no-index] takes two paths");
|
||||
|
||||
if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
|
||||
!is_outside_repo(argv[i], nongit, prefix)))
|
||||
return -1;
|
||||
|
||||
83
diff.c
83
diff.c
@@ -991,18 +991,23 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
|
||||
}
|
||||
}
|
||||
|
||||
struct diffstat_dir {
|
||||
struct diffstat_file **files;
|
||||
int nr, percent, cumulative;
|
||||
struct dirstat_file {
|
||||
const char *name;
|
||||
unsigned long changed;
|
||||
};
|
||||
|
||||
static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long changed, const char *base, int baselen)
|
||||
struct dirstat_dir {
|
||||
struct dirstat_file *files;
|
||||
int alloc, nr, percent, cumulative;
|
||||
};
|
||||
|
||||
static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long changed, const char *base, int baselen)
|
||||
{
|
||||
unsigned long this_dir = 0;
|
||||
unsigned int sources = 0;
|
||||
|
||||
while (dir->nr) {
|
||||
struct diffstat_file *f = *dir->files;
|
||||
struct dirstat_file *f = dir->files;
|
||||
int namelen = strlen(f->name);
|
||||
unsigned long this;
|
||||
char *slash;
|
||||
@@ -1017,10 +1022,7 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
|
||||
this = gather_dirstat(file, dir, changed, f->name, newbaselen);
|
||||
sources++;
|
||||
} else {
|
||||
if (f->is_unmerged || f->is_binary)
|
||||
this = 0;
|
||||
else
|
||||
this = f->added + f->deleted;
|
||||
this = f->changed;
|
||||
dir->files++;
|
||||
dir->nr--;
|
||||
sources += 2;
|
||||
@@ -1048,19 +1050,58 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
|
||||
return this_dir;
|
||||
}
|
||||
|
||||
static void show_dirstat(struct diffstat_t *data, struct diff_options *options)
|
||||
static void show_dirstat(struct diff_options *options)
|
||||
{
|
||||
int i;
|
||||
unsigned long changed;
|
||||
struct diffstat_dir dir;
|
||||
struct dirstat_dir dir;
|
||||
struct diff_queue_struct *q = &diff_queued_diff;
|
||||
|
||||
dir.files = NULL;
|
||||
dir.alloc = 0;
|
||||
dir.nr = 0;
|
||||
dir.percent = options->dirstat_percent;
|
||||
dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
|
||||
|
||||
/* Calculate total changes */
|
||||
changed = 0;
|
||||
for (i = 0; i < data->nr; i++) {
|
||||
if (data->files[i]->is_binary || data->files[i]->is_unmerged)
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
struct diff_filepair *p = q->queue[i];
|
||||
const char *name;
|
||||
unsigned long copied, added, damage;
|
||||
|
||||
name = p->one->path ? p->one->path : p->two->path;
|
||||
|
||||
if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
|
||||
diff_populate_filespec(p->one, 0);
|
||||
diff_populate_filespec(p->two, 0);
|
||||
diffcore_count_changes(p->one, p->two, NULL, NULL, 0,
|
||||
&copied, &added);
|
||||
diff_free_filespec_data(p->one);
|
||||
diff_free_filespec_data(p->two);
|
||||
} else if (DIFF_FILE_VALID(p->one)) {
|
||||
diff_populate_filespec(p->one, 1);
|
||||
copied = added = 0;
|
||||
diff_free_filespec_data(p->one);
|
||||
} else if (DIFF_FILE_VALID(p->two)) {
|
||||
diff_populate_filespec(p->two, 1);
|
||||
copied = 0;
|
||||
added = p->two->size;
|
||||
diff_free_filespec_data(p->two);
|
||||
} else
|
||||
continue;
|
||||
changed += data->files[i]->added;
|
||||
changed += data->files[i]->deleted;
|
||||
|
||||
/*
|
||||
* Original minus copied is the removed material,
|
||||
* added is the new material. They are both damages
|
||||
* made to the preimage.
|
||||
*/
|
||||
damage = (p->one->size - copied) + added;
|
||||
|
||||
ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
|
||||
dir.files[dir.nr].name = name;
|
||||
dir.files[dir.nr].changed = damage;
|
||||
changed += damage;
|
||||
dir.nr++;
|
||||
}
|
||||
|
||||
/* This can happen even with many files, if everything was renames */
|
||||
@@ -1068,10 +1109,6 @@ static void show_dirstat(struct diffstat_t *data, struct diff_options *options)
|
||||
return;
|
||||
|
||||
/* Show all directories with more than x% of the changes */
|
||||
dir.files = data->files;
|
||||
dir.nr = data->nr;
|
||||
dir.percent = options->dirstat_percent;
|
||||
dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
|
||||
gather_dirstat(options->file, &dir, changed, "", 0);
|
||||
}
|
||||
|
||||
@@ -3095,7 +3132,7 @@ void diff_flush(struct diff_options *options)
|
||||
separator++;
|
||||
}
|
||||
|
||||
if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIRSTAT)) {
|
||||
if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) {
|
||||
struct diffstat_t diffstat;
|
||||
|
||||
memset(&diffstat, 0, sizeof(struct diffstat_t));
|
||||
@@ -3105,8 +3142,6 @@ void diff_flush(struct diff_options *options)
|
||||
if (check_pair_status(p))
|
||||
diff_flush_stat(p, options, &diffstat);
|
||||
}
|
||||
if (output_format & DIFF_FORMAT_DIRSTAT)
|
||||
show_dirstat(&diffstat, options);
|
||||
if (output_format & DIFF_FORMAT_NUMSTAT)
|
||||
show_numstat(&diffstat, options);
|
||||
if (output_format & DIFF_FORMAT_DIFFSTAT)
|
||||
@@ -3116,6 +3151,8 @@ void diff_flush(struct diff_options *options)
|
||||
free_diffstat_info(&diffstat);
|
||||
separator++;
|
||||
}
|
||||
if (output_format & DIFF_FORMAT_DIRSTAT)
|
||||
show_dirstat(options);
|
||||
|
||||
if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
|
||||
for (i = 0; i < q->nr; i++)
|
||||
|
||||
@@ -112,8 +112,8 @@ static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
|
||||
struct diff_score {
|
||||
int src; /* index in rename_src */
|
||||
int dst; /* index in rename_dst */
|
||||
int score;
|
||||
int name_score;
|
||||
unsigned short score;
|
||||
short name_score;
|
||||
};
|
||||
|
||||
static int estimate_similarity(struct diff_filespec *src,
|
||||
@@ -223,6 +223,12 @@ static int score_compare(const void *a_, const void *b_)
|
||||
{
|
||||
const struct diff_score *a = a_, *b = b_;
|
||||
|
||||
/* sink the unused ones to the bottom */
|
||||
if (a->dst < 0)
|
||||
return (0 <= b->dst);
|
||||
else if (b->dst < 0)
|
||||
return -1;
|
||||
|
||||
if (a->score == b->score)
|
||||
return b->name_score - a->name_score;
|
||||
|
||||
@@ -387,6 +393,22 @@ static int find_exact_renames(void)
|
||||
return i;
|
||||
}
|
||||
|
||||
#define NUM_CANDIDATE_PER_DST 4
|
||||
static void record_if_better(struct diff_score m[], struct diff_score *o)
|
||||
{
|
||||
int i, worst;
|
||||
|
||||
/* find the worst one */
|
||||
worst = 0;
|
||||
for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
|
||||
if (score_compare(&m[i], &m[worst]) > 0)
|
||||
worst = i;
|
||||
|
||||
/* is it better than the worst one? */
|
||||
if (score_compare(&m[worst], o) > 0)
|
||||
m[worst] = *o;
|
||||
}
|
||||
|
||||
void diffcore_rename(struct diff_options *options)
|
||||
{
|
||||
int detect_rename = options->detect_rename;
|
||||
@@ -474,47 +496,61 @@ void diffcore_rename(struct diff_options *options)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mx = xmalloc(sizeof(*mx) * num_create * num_src);
|
||||
mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
|
||||
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
|
||||
int base = dst_cnt * num_src;
|
||||
struct diff_filespec *two = rename_dst[i].two;
|
||||
struct diff_score *m;
|
||||
|
||||
if (rename_dst[i].pair)
|
||||
continue; /* dealt with exact match already. */
|
||||
|
||||
m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
|
||||
for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
|
||||
m[j].dst = -1;
|
||||
|
||||
for (j = 0; j < rename_src_nr; j++) {
|
||||
struct diff_filespec *one = rename_src[j].one;
|
||||
struct diff_score *m = &mx[base+j];
|
||||
m->src = j;
|
||||
m->dst = i;
|
||||
m->score = estimate_similarity(one, two,
|
||||
minimum_score);
|
||||
m->name_score = basename_same(one, two);
|
||||
struct diff_score this_src;
|
||||
this_src.score = estimate_similarity(one, two,
|
||||
minimum_score);
|
||||
this_src.name_score = basename_same(one, two);
|
||||
this_src.dst = i;
|
||||
this_src.src = j;
|
||||
record_if_better(m, &this_src);
|
||||
diff_free_filespec_blob(one);
|
||||
}
|
||||
/* We do not need the text anymore */
|
||||
diff_free_filespec_blob(two);
|
||||
dst_cnt++;
|
||||
}
|
||||
|
||||
/* cost matrix sorted by most to least similar pair */
|
||||
qsort(mx, num_create * num_src, sizeof(*mx), score_compare);
|
||||
for (i = 0; i < num_create * num_src; i++) {
|
||||
struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
|
||||
struct diff_filespec *src;
|
||||
qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);
|
||||
|
||||
for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
|
||||
struct diff_rename_dst *dst;
|
||||
|
||||
if ((mx[i].dst < 0) ||
|
||||
(mx[i].score < minimum_score))
|
||||
break; /* there is no more usable pair. */
|
||||
dst = &rename_dst[mx[i].dst];
|
||||
if (dst->pair)
|
||||
continue; /* already done, either exact or fuzzy. */
|
||||
if (mx[i].score < minimum_score)
|
||||
break; /* there is no more usable pair. */
|
||||
src = rename_src[mx[i].src].one;
|
||||
if (src->rename_used)
|
||||
if (rename_src[mx[i].src].one->rename_used)
|
||||
continue;
|
||||
record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
|
||||
rename_count++;
|
||||
}
|
||||
for (i = 0; i < num_create * num_src; i++) {
|
||||
struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
|
||||
|
||||
for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
|
||||
struct diff_rename_dst *dst;
|
||||
|
||||
if ((mx[i].dst < 0) ||
|
||||
(mx[i].score < minimum_score))
|
||||
break; /* there is no more usable pair. */
|
||||
dst = &rename_dst[mx[i].dst];
|
||||
if (dst->pair)
|
||||
continue; /* already done, either exact or fuzzy. */
|
||||
if (mx[i].score < minimum_score)
|
||||
break; /* there is no more usable pair. */
|
||||
record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
|
||||
rename_count++;
|
||||
}
|
||||
|
||||
2
dir.c
2
dir.c
@@ -80,7 +80,7 @@ static int match_one(const char *match, const char *name, int namelen)
|
||||
if (strncmp(match, name, matchlen))
|
||||
return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;
|
||||
|
||||
if (!name[matchlen])
|
||||
if (namelen == matchlen)
|
||||
return MATCHED_EXACTLY;
|
||||
if (match[matchlen-1] == '/' || name[matchlen] == '/')
|
||||
return MATCHED_RECURSIVELY;
|
||||
|
||||
@@ -550,6 +550,21 @@ sub parse_diff {
|
||||
return @hunk;
|
||||
}
|
||||
|
||||
sub parse_diff_header {
|
||||
my $src = shift;
|
||||
|
||||
my $head = { TEXT => [], DISPLAY => [] };
|
||||
my $mode = { TEXT => [], DISPLAY => [] };
|
||||
|
||||
for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
|
||||
my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
|
||||
$mode : $head;
|
||||
push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
|
||||
push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
|
||||
}
|
||||
return ($head, $mode);
|
||||
}
|
||||
|
||||
sub hunk_splittable {
|
||||
my ($text) = @_;
|
||||
|
||||
@@ -795,9 +810,40 @@ sub patch_update_file {
|
||||
my ($ix, $num);
|
||||
my $path = shift;
|
||||
my ($head, @hunk) = parse_diff($path);
|
||||
($head, my $mode) = parse_diff_header($head);
|
||||
for (@{$head->{DISPLAY}}) {
|
||||
print;
|
||||
}
|
||||
|
||||
if (@{$mode->{TEXT}}) {
|
||||
while (1) {
|
||||
print @{$mode->{DISPLAY}};
|
||||
print colored $prompt_color,
|
||||
"Stage mode change [y/n/a/d/?]? ";
|
||||
my $line = <STDIN>;
|
||||
if ($line =~ /^y/i) {
|
||||
$mode->{USE} = 1;
|
||||
last;
|
||||
}
|
||||
elsif ($line =~ /^n/i) {
|
||||
$mode->{USE} = 0;
|
||||
last;
|
||||
}
|
||||
elsif ($line =~ /^a/i) {
|
||||
$_->{USE} = 1 foreach ($mode, @hunk);
|
||||
last;
|
||||
}
|
||||
elsif ($line =~ /^d/i) {
|
||||
$_->{USE} = 0 foreach ($mode, @hunk);
|
||||
last;
|
||||
}
|
||||
else {
|
||||
help_patch_cmd('');
|
||||
next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$num = scalar @hunk;
|
||||
$ix = 0;
|
||||
|
||||
@@ -920,6 +966,9 @@ sub patch_update_file {
|
||||
|
||||
my $n_lofs = 0;
|
||||
my @result = ();
|
||||
if ($mode->{USE}) {
|
||||
push @result, @{$mode->{TEXT}};
|
||||
}
|
||||
for (@hunk) {
|
||||
my $text = $_->{TEXT};
|
||||
my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
|
||||
|
||||
32
git-am.sh
32
git-am.sh
@@ -107,7 +107,7 @@ It does not apply to blobs recorded in its index."
|
||||
# patch did not touch, so recursive ends up canceling them,
|
||||
# saying that we reverted all those changes.
|
||||
|
||||
eval GITHEAD_$his_tree='"$SUBJECT"'
|
||||
eval GITHEAD_$his_tree='"$FIRSTLINE"'
|
||||
export GITHEAD_$his_tree
|
||||
git-merge-recursive $orig_tree -- HEAD $his_tree || {
|
||||
git rerere
|
||||
@@ -117,10 +117,6 @@ It does not apply to blobs recorded in its index."
|
||||
unset GITHEAD_$his_tree
|
||||
}
|
||||
|
||||
reread_subject () {
|
||||
git stripspace <"$1" | sed -e 1q
|
||||
}
|
||||
|
||||
prec=4
|
||||
dotest=".dotest"
|
||||
sign= utf8=t keep= skip= interactive= resolved= binary= rebasing=
|
||||
@@ -331,7 +327,20 @@ do
|
||||
echo "Patch is empty. Was it split wrong?"
|
||||
stop_here $this
|
||||
}
|
||||
git stripspace < "$dotest/msg" > "$dotest/msg-clean"
|
||||
if test -f "$dotest/rebasing" &&
|
||||
commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \
|
||||
-e q "$dotest/$msgnum") &&
|
||||
test "$(git cat-file -t "$commit")" = commit
|
||||
then
|
||||
git cat-file commit "$commit" |
|
||||
sed -e '1,/^$/d' >"$dotest/msg-clean"
|
||||
else
|
||||
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
|
||||
case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
|
||||
|
||||
(printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") |
|
||||
git stripspace > "$dotest/msg-clean"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -347,9 +356,6 @@ do
|
||||
|
||||
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
|
||||
|
||||
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
|
||||
case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
|
||||
|
||||
case "$resume" in
|
||||
'')
|
||||
if test '' != "$SIGNOFF"
|
||||
@@ -368,10 +374,8 @@ do
|
||||
ADD_SIGNOFF=
|
||||
fi
|
||||
{
|
||||
printf '%s\n' "$SUBJECT"
|
||||
if test -s "$dotest/msg-clean"
|
||||
then
|
||||
echo
|
||||
cat "$dotest/msg-clean"
|
||||
fi
|
||||
if test '' != "$ADD_SIGNOFF"
|
||||
@@ -408,7 +412,6 @@ do
|
||||
[aA]*) action=yes interactive= ;;
|
||||
[nN]*) action=skip ;;
|
||||
[eE]*) git_editor "$dotest/final-commit"
|
||||
SUBJECT=$(reread_subject "$dotest/final-commit")
|
||||
action=again ;;
|
||||
[vV]*) action=again
|
||||
LESS=-S ${PAGER:-less} "$dotest/patch" ;;
|
||||
@@ -418,6 +421,7 @@ do
|
||||
else
|
||||
action=yes
|
||||
fi
|
||||
FIRSTLINE=$(head -1 "$dotest/final-commit")
|
||||
|
||||
if test $action = skip
|
||||
then
|
||||
@@ -431,7 +435,7 @@ do
|
||||
stop_here $this
|
||||
fi
|
||||
|
||||
printf 'Applying %s\n' "$SUBJECT"
|
||||
printf 'Applying %s\n' "$FIRSTLINE"
|
||||
|
||||
case "$resolved" in
|
||||
'')
|
||||
@@ -489,7 +493,7 @@ do
|
||||
tree=$(git write-tree) &&
|
||||
parent=$(git rev-parse --verify HEAD) &&
|
||||
commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit") &&
|
||||
git update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
|
||||
git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
|
||||
stop_here $this
|
||||
|
||||
if test -x "$GIT_DIR"/hooks/post-applypatch
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
USAGE='[start|bad|good|skip|next|reset|visualize|replay|log|run]'
|
||||
LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
|
||||
USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
|
||||
LONG_USAGE='git bisect help
|
||||
print this long help message.
|
||||
git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
|
||||
reset bisect state and start bisection.
|
||||
git bisect bad [<rev>]
|
||||
mark <rev> a known-bad revision.
|
||||
@@ -20,7 +22,9 @@ git bisect replay <logfile>
|
||||
git bisect log
|
||||
show bisect log.
|
||||
git bisect run <cmd>...
|
||||
use <cmd>... to automatically bisect.'
|
||||
use <cmd>... to automatically bisect.
|
||||
|
||||
Please use "git help bisect" to get the full man page.'
|
||||
|
||||
OPTIONS_SPEC=
|
||||
. git-sh-setup
|
||||
@@ -62,9 +66,10 @@ bisect_start() {
|
||||
# Verify HEAD. If we were bisecting before this, reset to the
|
||||
# top-of-line master first!
|
||||
#
|
||||
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) ||
|
||||
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
|
||||
head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
|
||||
die "Bad HEAD - I need a HEAD"
|
||||
start_head=''
|
||||
case "$head" in
|
||||
refs/heads/bisect)
|
||||
if [ -s "$GIT_DIR/BISECT_START" ]; then
|
||||
@@ -78,7 +83,7 @@ bisect_start() {
|
||||
# This error message should only be triggered by cogito usage,
|
||||
# and cogito users should understand it relates to cg-seek.
|
||||
[ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
|
||||
echo "${head#refs/heads/}" >"$GIT_DIR/BISECT_START"
|
||||
start_head="${head#refs/heads/}"
|
||||
;;
|
||||
*)
|
||||
die "Bad HEAD - strange symbolic ref"
|
||||
@@ -99,6 +104,7 @@ bisect_start() {
|
||||
done
|
||||
orig_args=$(sq "$@")
|
||||
bad_seen=0
|
||||
eval=''
|
||||
while [ $# -gt 0 ]; do
|
||||
arg="$1"
|
||||
case "$arg" in
|
||||
@@ -116,13 +122,15 @@ bisect_start() {
|
||||
0) state='bad' ; bad_seen=1 ;;
|
||||
*) state='good' ;;
|
||||
esac
|
||||
bisect_write "$state" "$rev" 'nolog'
|
||||
eval="$eval bisect_write '$state' '$rev' 'nolog'; "
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
||||
test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START"
|
||||
eval "$eval"
|
||||
echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
|
||||
bisect_auto_next
|
||||
}
|
||||
@@ -151,20 +159,18 @@ bisect_state() {
|
||||
rev=$(git rev-parse --verify HEAD) ||
|
||||
die "Bad rev input: HEAD"
|
||||
bisect_write "$state" "$rev" ;;
|
||||
2,bad)
|
||||
rev=$(git rev-parse --verify "$2^{commit}") ||
|
||||
die "Bad rev input: $2"
|
||||
bisect_write "$state" "$rev" ;;
|
||||
*,good|*,skip)
|
||||
2,bad|*,good|*,skip)
|
||||
shift
|
||||
revs=$(git rev-parse --revs-only --no-flags "$@") &&
|
||||
test '' != "$revs" || die "Bad rev input: $@"
|
||||
for rev in $revs
|
||||
eval=''
|
||||
for rev in "$@"
|
||||
do
|
||||
rev=$(git rev-parse --verify "$rev^{commit}") ||
|
||||
die "Bad rev commit: $rev^{commit}"
|
||||
bisect_write "$state" "$rev"
|
||||
done ;;
|
||||
sha=$(git rev-parse --verify "$rev^{commit}") ||
|
||||
die "Bad rev input: $rev"
|
||||
eval="$eval bisect_write '$state' '$sha'; "
|
||||
done
|
||||
eval "$eval" ;;
|
||||
*,bad)
|
||||
die "'git bisect bad' can take only one argument." ;;
|
||||
*)
|
||||
usage ;;
|
||||
esac
|
||||
@@ -465,6 +471,8 @@ case "$#" in
|
||||
cmd="$1"
|
||||
shift
|
||||
case "$cmd" in
|
||||
help)
|
||||
git bisect -h ;;
|
||||
start)
|
||||
bisect_start "$@" ;;
|
||||
bad|good|skip)
|
||||
|
||||
@@ -269,6 +269,7 @@ fi
|
||||
if test -n "$2"
|
||||
then
|
||||
dir="$2"
|
||||
test $# = 2 || die "excess parameter to git-clone"
|
||||
else
|
||||
# Derive one from the repository name
|
||||
# Try using "humanish" part of source repo if user didn't specify one
|
||||
|
||||
@@ -291,6 +291,12 @@ static inline void *xmalloc(size_t size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
|
||||
* "data" to the allocated memory, zero terminates the allocated memory,
|
||||
* and returns a pointer to the allocated memory. If the allocation fails,
|
||||
* the program dies.
|
||||
*/
|
||||
static inline void *xmemdupz(const void *data, size_t len)
|
||||
{
|
||||
char *p = xmalloc(len + 1);
|
||||
@@ -352,6 +358,11 @@ static inline void *xmmap(void *start, size_t length,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* xread() is the same a read(), but it automatically restarts read()
|
||||
* operations with a recoverable error (EAGAIN and EINTR). xread()
|
||||
* DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
|
||||
*/
|
||||
static inline ssize_t xread(int fd, void *buf, size_t len)
|
||||
{
|
||||
ssize_t nr;
|
||||
@@ -363,6 +374,11 @@ static inline ssize_t xread(int fd, void *buf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* xwrite() is the same a write(), but it automatically restarts write()
|
||||
* operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
|
||||
* GUARANTEE that "len" bytes is written even if the operation is successful.
|
||||
*/
|
||||
static inline ssize_t xwrite(int fd, const void *buf, size_t len)
|
||||
{
|
||||
ssize_t nr;
|
||||
|
||||
@@ -772,7 +772,7 @@ sub commit {
|
||||
waitpid($pid,0);
|
||||
die "Error running git-commit-tree: $?\n" if $?;
|
||||
|
||||
system("git-update-ref $remote/$branch $cid") == 0
|
||||
system('git-update-ref', "$remote/$branch", $cid) == 0
|
||||
or die "Cannot write branch $branch for update: $!\n";
|
||||
|
||||
if ($tag) {
|
||||
|
||||
@@ -309,22 +309,42 @@ then
|
||||
}
|
||||
fi
|
||||
|
||||
# If the branch to rebase is given, first switch to it.
|
||||
# If the branch to rebase is given, that is the branch we will rebase
|
||||
# $branch_name -- branch being rebased, or HEAD (already detached)
|
||||
# $orig_head -- commit object name of tip of the branch before rebasing
|
||||
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
|
||||
switch_to=
|
||||
case "$#" in
|
||||
2)
|
||||
# Is it "rebase other $branchname" or "rebase other $commit"?
|
||||
branch_name="$2"
|
||||
git-checkout "$2" || usage
|
||||
;;
|
||||
*)
|
||||
if branch_name=`git symbolic-ref -q HEAD`
|
||||
switch_to="$2"
|
||||
|
||||
if git show-ref --verify --quiet -- "refs/heads/$2" &&
|
||||
branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null)
|
||||
then
|
||||
branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
|
||||
head_name="refs/heads/$2"
|
||||
elif branch=$(git rev-parse --verify "$2" 2>/dev/null)
|
||||
then
|
||||
head_name="detached HEAD"
|
||||
else
|
||||
branch_name=HEAD ;# detached
|
||||
usage
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Do not need to switch branches, we are already on it.
|
||||
if branch_name=`git symbolic-ref -q HEAD`
|
||||
then
|
||||
head_name=$branch_name
|
||||
branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
|
||||
else
|
||||
head_name="detached HEAD"
|
||||
branch_name=HEAD ;# detached
|
||||
fi
|
||||
branch=$(git rev-parse --verify "${branch_name}^0") || exit
|
||||
;;
|
||||
esac
|
||||
branch=$(git rev-parse --verify "${branch_name}^0") || exit
|
||||
orig_head=$branch
|
||||
|
||||
# Now we are rebasing commits $upstream..$branch on top of $onto
|
||||
|
||||
@@ -335,6 +355,8 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
|
||||
# linear history?
|
||||
! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
|
||||
then
|
||||
# Lazily switch to the target branch if needed...
|
||||
test -z "$switch_to" || git checkout "$switch_to"
|
||||
echo >&2 "Current branch $branch_name is up to date."
|
||||
exit 0
|
||||
fi
|
||||
@@ -346,22 +368,11 @@ then
|
||||
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
|
||||
fi
|
||||
|
||||
# move to a detached HEAD
|
||||
orig_head=$(git rev-parse HEAD^0)
|
||||
head_name=$(git symbolic-ref HEAD 2> /dev/null)
|
||||
case "$head_name" in
|
||||
'')
|
||||
head_name="detached HEAD"
|
||||
;;
|
||||
*)
|
||||
git checkout "$orig_head" > /dev/null 2>&1 ||
|
||||
die "could not detach HEAD"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
|
||||
# Detach HEAD and reset the tree
|
||||
echo "First, rewinding head to replay your work on top of it..."
|
||||
git-reset --hard "$onto"
|
||||
git checkout "$onto^0" >/dev/null 2>&1 ||
|
||||
die "could not detach HEAD"
|
||||
# git reset --hard "$onto^0"
|
||||
|
||||
# If the $onto is a proper descendant of the tip of the branch, then
|
||||
# we just fast forwarded.
|
||||
@@ -374,7 +385,8 @@ fi
|
||||
|
||||
if test -z "$do_merge"
|
||||
then
|
||||
git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
|
||||
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
|
||||
"$upstream..$orig_head" |
|
||||
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
|
||||
move_to_original_branch
|
||||
ret=$?
|
||||
@@ -397,7 +409,7 @@ echo "$orig_head" > "$dotest/orig-head"
|
||||
echo "$head_name" > "$dotest/head-name"
|
||||
|
||||
msgnum=0
|
||||
for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
|
||||
for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
|
||||
do
|
||||
msgnum=$(($msgnum + 1))
|
||||
echo "$cmt" > "$dotest/cmt.$msgnum"
|
||||
|
||||
@@ -168,7 +168,8 @@ my $envelope_sender;
|
||||
# Example reply to:
|
||||
#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
|
||||
|
||||
my $repo = Git->repository();
|
||||
my $repo = eval { Git->repository() };
|
||||
my @repo = $repo ? ($repo) : ();
|
||||
my $term = eval {
|
||||
$ENV{"GIT_SEND_EMAIL_NOTTY"}
|
||||
? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
|
||||
@@ -271,25 +272,25 @@ sub read_config {
|
||||
|
||||
foreach my $setting (keys %config_bool_settings) {
|
||||
my $target = $config_bool_settings{$setting}->[0];
|
||||
$$target = $repo->config_bool("$prefix.$setting") unless (defined $$target);
|
||||
$$target = Git::config_bool(@repo, "$prefix.$setting") unless (defined $$target);
|
||||
}
|
||||
|
||||
foreach my $setting (keys %config_settings) {
|
||||
my $target = $config_settings{$setting};
|
||||
if (ref($target) eq "ARRAY") {
|
||||
unless (@$target) {
|
||||
my @values = $repo->config("$prefix.$setting");
|
||||
my @values = Git::config(@repo, "$prefix.$setting");
|
||||
@$target = @values if (@values && defined $values[0]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$$target = $repo->config("$prefix.$setting") unless (defined $$target);
|
||||
$$target = Git::config(@repo, "$prefix.$setting") unless (defined $$target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# read configuration from [sendemail "$identity"], fall back on [sendemail]
|
||||
$identity = $repo->config("sendemail.identity") unless (defined $identity);
|
||||
$identity = Git::config(@repo, "sendemail.identity") unless (defined $identity);
|
||||
read_config("sendemail.$identity") if (defined $identity);
|
||||
read_config("sendemail");
|
||||
|
||||
@@ -327,8 +328,9 @@ if (0) {
|
||||
}
|
||||
}
|
||||
|
||||
my ($repoauthor) = $repo->ident_person('author');
|
||||
my ($repocommitter) = $repo->ident_person('committer');
|
||||
my ($repoauthor, $repocommitter);
|
||||
($repoauthor) = Git::ident_person(@repo, 'author');
|
||||
($repocommitter) = Git::ident_person(@repo, 'committer');
|
||||
|
||||
# Verify the user input
|
||||
|
||||
@@ -415,7 +417,7 @@ if (@files) {
|
||||
|
||||
my $prompting = 0;
|
||||
if (!defined $sender) {
|
||||
$sender = $repoauthor || $repocommitter;
|
||||
$sender = $repoauthor || $repocommitter || '';
|
||||
|
||||
while (1) {
|
||||
$_ = $term->readline("Who should the emails appear to be from? [$sender] ");
|
||||
@@ -509,7 +511,7 @@ GIT: for the patch you are writing.
|
||||
EOT
|
||||
close(C);
|
||||
|
||||
my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
|
||||
my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
|
||||
system('sh', '-c', '$0 $@', $editor, $compose_filename);
|
||||
|
||||
open(C2,">",$compose_filename . ".final")
|
||||
|
||||
@@ -327,7 +327,8 @@ set_name_rev () {
|
||||
cd "$1" && {
|
||||
git describe "$2" 2>/dev/null ||
|
||||
git describe --tags "$2" 2>/dev/null ||
|
||||
git describe --contains --tags "$2"
|
||||
git describe --contains "$2" 2>/dev/null ||
|
||||
git describe --all --always "$2"
|
||||
}
|
||||
) )
|
||||
test -z "$revname" || revname=" ($revname)"
|
||||
@@ -342,6 +343,7 @@ set_name_rev () {
|
||||
#
|
||||
cmd_summary() {
|
||||
summary_limit=-1
|
||||
for_status=
|
||||
|
||||
# parse $args after "submodule ... summary".
|
||||
while test $# -ne 0
|
||||
@@ -350,6 +352,9 @@ cmd_summary() {
|
||||
--cached)
|
||||
cached="$1"
|
||||
;;
|
||||
--for-status)
|
||||
for_status="$1"
|
||||
;;
|
||||
-n|--summary-limit)
|
||||
if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
|
||||
then
|
||||
@@ -397,7 +402,8 @@ cmd_summary() {
|
||||
done
|
||||
)
|
||||
|
||||
test -n "$modules" &&
|
||||
test -z "$modules" && return
|
||||
|
||||
git diff-index $cached --raw $head -- $modules |
|
||||
grep -e '^:160000' -e '^:[0-7]* 160000' |
|
||||
cut -c2- |
|
||||
@@ -499,7 +505,14 @@ cmd_summary() {
|
||||
echo
|
||||
fi
|
||||
echo
|
||||
done
|
||||
done |
|
||||
if test -n "$for_status"; then
|
||||
echo "# Modified submodules:"
|
||||
echo "#"
|
||||
sed -e 's|^|# |' -e 's|^# $|#|'
|
||||
else
|
||||
cat
|
||||
fi
|
||||
}
|
||||
#
|
||||
# List all submodules, prefixed with:
|
||||
|
||||
15
git-svn.perl
15
git-svn.perl
@@ -410,10 +410,12 @@ sub cmd_dcommit {
|
||||
$head ||= 'HEAD';
|
||||
my @refs;
|
||||
my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
|
||||
print "Committing to $url ...\n";
|
||||
if ($url) {
|
||||
print "Committing to $url ...\n";
|
||||
}
|
||||
unless ($gs) {
|
||||
die "Unable to determine upstream SVN information from ",
|
||||
"$head history\n";
|
||||
"$head history.\nPerhaps the repository is empty.";
|
||||
}
|
||||
my $last_rev;
|
||||
my ($linear_refs, $parents) = linearize_history($gs, \@refs);
|
||||
@@ -1120,7 +1122,7 @@ sub cmt_metadata {
|
||||
|
||||
sub working_head_info {
|
||||
my ($head, $refs) = @_;
|
||||
my @args = ('log', '--no-color', '--first-parent');
|
||||
my @args = ('log', '--no-color', '--first-parent', '--pretty=medium');
|
||||
my ($fh, $ctx) = command_output_pipe(@args, $head);
|
||||
my $hash;
|
||||
my %max;
|
||||
@@ -2375,8 +2377,7 @@ sub check_author {
|
||||
my ($author) = @_;
|
||||
if (!defined $author || length $author == 0) {
|
||||
$author = '(no author)';
|
||||
}
|
||||
if (defined $::_authors && ! defined $::users{$author}) {
|
||||
} elsif (defined $::_authors && ! defined $::users{$author}) {
|
||||
die "Author: $author not defined in $::_authors file\n";
|
||||
}
|
||||
$author;
|
||||
@@ -2519,6 +2520,7 @@ sub rebuild_from_rev_db {
|
||||
my ($self, $path) = @_;
|
||||
my $r = -1;
|
||||
open my $fh, '<', $path or croak "open: $!";
|
||||
binmode $fh or croak "binmode: $!";
|
||||
while (<$fh>) {
|
||||
length($_) == 41 or croak "inconsistent size in ($_) != 41";
|
||||
chomp($_);
|
||||
@@ -2616,6 +2618,7 @@ sub rebuild {
|
||||
sub _rev_map_set {
|
||||
my ($fh, $rev, $commit) = @_;
|
||||
|
||||
binmode $fh or croak "binmode: $!";
|
||||
my $size = (stat($fh))[7];
|
||||
($size % 24) == 0 or croak "inconsistent size: $size";
|
||||
|
||||
@@ -2719,6 +2722,7 @@ sub rev_map_max {
|
||||
my $map_path = $self->map_path;
|
||||
stat $map_path or return $want_commit ? (0, undef) : 0;
|
||||
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
|
||||
binmode $fh or croak "binmode: $!";
|
||||
my $size = (stat($fh))[7];
|
||||
($size % 24) == 0 or croak "inconsistent size: $size";
|
||||
|
||||
@@ -2751,6 +2755,7 @@ sub rev_map_get {
|
||||
return undef unless -e $map_path;
|
||||
|
||||
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
|
||||
binmode $fh or croak "binmode: $!";
|
||||
my $size = (stat($fh))[7];
|
||||
($size % 24) == 0 or croak "inconsistent size: $size";
|
||||
|
||||
|
||||
2
git.c
2
git.c
@@ -347,7 +347,7 @@ static void handle_internal_command(int argc, const char **argv)
|
||||
{ "shortlog", cmd_shortlog, USE_PAGER },
|
||||
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
||||
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
||||
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE | USE_PAGER },
|
||||
{ "stripspace", cmd_stripspace },
|
||||
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
||||
{ "tag", cmd_tag, RUN_SETUP },
|
||||
|
||||
@@ -29,40 +29,40 @@ Build time configuration
|
||||
See also "How to configure gitweb for your local system" in README
|
||||
file for gitweb (in gitweb/README).
|
||||
|
||||
- There are many configuration variables which affects building of
|
||||
- There are many configuration variables which affect building of
|
||||
gitweb.cgi; see "default configuration for gitweb" section in main
|
||||
(top dir) Makefile, and instructions for building gitweb/gitweb.cgi
|
||||
target.
|
||||
|
||||
One of most important is where to find git wrapper binary. Gitweb
|
||||
tries to find git wrapper at $(bindir)/git, so you have to set $bindir
|
||||
One of the most important is where to find the git wrapper binary. Gitweb
|
||||
tries to find the git wrapper at $(bindir)/git, so you have to set $bindir
|
||||
when building gitweb.cgi, or $prefix from which $bindir is derived. If
|
||||
you build and install gitweb together with the rest of git suite,
|
||||
you build and install gitweb together with the rest of the git suite,
|
||||
there should be no problems. Otherwise, if git was for example
|
||||
installed from a binary package, you have to set $prefix (or $bindir)
|
||||
accordingly.
|
||||
|
||||
- Another important issue is where are git repositories you want to make
|
||||
available to gitweb. By default gitweb search for repositories under
|
||||
available to gitweb. By default gitweb searches for repositories under
|
||||
/pub/git; if you want to have projects somewhere else, like /home/git,
|
||||
use GITWEB_PROJECTROOT build configuration variable.
|
||||
|
||||
By default all git repositories under projectroot are visible and
|
||||
available to gitweb. List of projects is generated by default by
|
||||
available to gitweb. The list of projects is generated by default by
|
||||
scanning the projectroot directory for git repositories. This can be
|
||||
changed (configured) as described in "Gitweb repositories" section
|
||||
below.
|
||||
|
||||
Note that gitweb deals directly with object database, and does not
|
||||
need working directory; the name of the project is the name of its
|
||||
Note that gitweb deals directly with the object database, and does not
|
||||
need a working directory; the name of the project is the name of its
|
||||
repository object database, usually projectname.git for bare
|
||||
repositories. If you want to provide gitweb access to non-bare (live)
|
||||
repository, you can make projectname.git symbolic link under
|
||||
repositories, you can make projectname.git a symbolic link under
|
||||
projectroot linking to projectname/.git (but it is just
|
||||
a suggestion).
|
||||
|
||||
- You can control where gitweb tries to find its main CSS style file,
|
||||
its favicon and logo with GITWEB_CSS, GITWEB_FAVICON and GITWEB_LOGO
|
||||
its favicon and logo with the GITWEB_CSS, GITWEB_FAVICON and GITWEB_LOGO
|
||||
build configuration variables. By default gitweb tries to find them
|
||||
in the same directory as gitweb.cgi script.
|
||||
|
||||
@@ -91,13 +91,17 @@ Gitweb config file
|
||||
See also "Runtime gitweb configuration" section in README file
|
||||
for gitweb (in gitweb/README).
|
||||
|
||||
- You can configure gitweb further using gitweb configuration file;
|
||||
by default it is file named gitweb_config.perl in the same place as
|
||||
gitweb.cgi script. You can control default place for config file
|
||||
using GITWEB_CONFIG build configuration variable, and you can set it
|
||||
using GITWEB_CONFIG environmental variable.
|
||||
- You can configure gitweb further using the gitweb configuration file;
|
||||
by default this is a file named gitweb_config.perl in the same place as
|
||||
gitweb.cgi script. You can control the default place for the config file
|
||||
using the GITWEB_CONFIG build configuration variable, and you can set it
|
||||
using the GITWEB_CONFIG environment variable. If this file does not
|
||||
exist, gitweb looks for a system-wide configuration file, normally
|
||||
/etc/gitweb.conf. You can change the default using the
|
||||
GITWEB_CONFIG_SYSTEM build configuration variable, and override it
|
||||
through the GITWEB_CONFIG_SYSTEM environment variable.
|
||||
|
||||
- Gitweb config file is [fragment] of perl code. You can set variables
|
||||
- The gitweb config file is a fragment of perl code. You can set variables
|
||||
using "our $variable = value"; text from "#" character until the end
|
||||
of a line is ignored. See perlsyn(1) for details.
|
||||
|
||||
@@ -124,36 +128,37 @@ Gitweb repositories
|
||||
-------------------
|
||||
|
||||
- By default all git repositories under projectroot are visible and
|
||||
available to gitweb. List of projects is generated by default by
|
||||
available to gitweb. The list of projects is generated by default by
|
||||
scanning the projectroot directory for git repositories (for object
|
||||
databases to be more exact).
|
||||
|
||||
You can provide pre-generated list of [visible] repositories,
|
||||
You can provide a pre-generated list of [visible] repositories,
|
||||
together with information about their owners (the project ownership
|
||||
is taken from owner of repository directory otherwise), by setting
|
||||
GITWEB_LIST build configuration variable (or $projects_list variable
|
||||
in gitweb config file) to point to a plain file.
|
||||
defaults to the owner of the repository directory otherwise), by setting
|
||||
the GITWEB_LIST build configuration variable (or the $projects_list
|
||||
variable in the gitweb config file) to point to a plain file.
|
||||
|
||||
Each line of projects list file should consist of url-encoded path
|
||||
to project repository database (relative to projectroot) separated
|
||||
by space from url-encoded project owner; spaces in both project path
|
||||
and project owner have to be encoded as either '%20' or '+'.
|
||||
Each line of the projects list file should consist of the url-encoded path
|
||||
to the project repository database (relative to projectroot), followed
|
||||
by the url-encoded project owner on the same line (separated by a space).
|
||||
Spaces in both project path and project owner have to be encoded as either
|
||||
'%20' or '+'.
|
||||
|
||||
You can generate projects list index file using project_index action
|
||||
(the 'TXT' link on projects list page) directly from gitweb.
|
||||
You can generate the projects list index file using the project_index
|
||||
action (the 'TXT' link on projects list page) directly from gitweb.
|
||||
|
||||
- By default even if project is not visible on projects list page, you
|
||||
can view it nevertheless by hand-crafting gitweb URL. You can set
|
||||
GITWEB_STRICT_EXPORT build configuration variable (or $strict_export
|
||||
variable in gitweb config file) to only allow viewing of
|
||||
- By default, even if a project is not visible on projects list page, you
|
||||
can view it nevertheless by hand-crafting a gitweb URL. You can set the
|
||||
GITWEB_STRICT_EXPORT build configuration variable (or the $strict_export
|
||||
variable in the gitweb config file) to only allow viewing of
|
||||
repositories also shown on the overview page.
|
||||
|
||||
- Alternatively, you can configure gitweb to only list and allow
|
||||
viewing of the explicitly exported repositories, via
|
||||
GITWEB_EXPORT_OK build configuration variable (or $export_ok
|
||||
viewing of the explicitly exported repositories, via the
|
||||
GITWEB_EXPORT_OK build configuration variable (or the $export_ok
|
||||
variable in gitweb config file). If it evaluates to true, gitweb
|
||||
show repository only if this file exists in its object database
|
||||
(if directory has the magic file $export_ok).
|
||||
shows repositories only if this file exists in its object database
|
||||
(if directory has the magic file named $export_ok).
|
||||
|
||||
Generating projects list using gitweb
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2,7 +2,7 @@ GIT web Interface
|
||||
=================
|
||||
|
||||
The one working on:
|
||||
http://www.kernel.org/git/
|
||||
http://git.kernel.org/
|
||||
|
||||
From the git version 1.4.0 gitweb is bundled with git.
|
||||
|
||||
@@ -10,13 +10,13 @@ From the git version 1.4.0 gitweb is bundled with git.
|
||||
How to configure gitweb for your local system
|
||||
---------------------------------------------
|
||||
|
||||
See also "Build time configuration" section in INSTALL
|
||||
See also the "Build time configuration" section in the INSTALL
|
||||
file for gitweb (in gitweb/INSTALL).
|
||||
|
||||
You can specify the following configuration variables when building GIT:
|
||||
* GIT_BINDIR
|
||||
Points out where to find git executable. You should set up it to
|
||||
the place where git binary was installed (usually /usr/bin) if you
|
||||
Points where to find the git executable. You should set it up to
|
||||
the place where the git binary was installed (usually /usr/bin) if you
|
||||
don't install git from sources together with gitweb. [Default: $(bindir)]
|
||||
* GITWEB_SITENAME
|
||||
Shown in the title of all generated pages, defaults to the server name
|
||||
@@ -24,13 +24,13 @@ You can specify the following configuration variables when building GIT:
|
||||
* GITWEB_PROJECTROOT
|
||||
The root directory for all projects shown by gitweb. Must be set
|
||||
correctly for gitweb to find repositories to display. See also
|
||||
"Gitweb repositories" in INSTALL file for gitweb. [Default: /pub/git]
|
||||
"Gitweb repositories" in the INSTALL file for gitweb. [Default: /pub/git]
|
||||
* GITWEB_PROJECT_MAXDEPTH
|
||||
The filesystem traversing limit for getting projects list; the number
|
||||
The filesystem traversing limit for getting the project list; the number
|
||||
is taken as depth relative to the projectroot. It is used when
|
||||
GITWEB_LIST is a directory (or is not set; then project root is used).
|
||||
Is is meant to speed up project listing on large work trees by limiting
|
||||
find depth. [Default: 2007]
|
||||
search depth. [Default: 2007]
|
||||
* GITWEB_LIST
|
||||
Points to a directory to scan for projects (defaults to project root
|
||||
if not set / if empty) or to a file with explicit listing of projects
|
||||
@@ -72,15 +72,15 @@ You can specify the following configuration variables when building GIT:
|
||||
Git base URLs used for URL to where fetch project from, i.e. full
|
||||
URL is "$git_base_url/$project". Shown on projects summary page.
|
||||
Repository URL for project can be also configured per repository; this
|
||||
takes precendence over URL composed from base URL and project name.
|
||||
takes precedence over URLs composed from base URL and a project name.
|
||||
Note that you can setup multiple base URLs (for example one for
|
||||
git:// protocol access, one for http:// access) from gitweb config
|
||||
file. [No default]
|
||||
git:// protocol access, another for http:// access) from the gitweb
|
||||
config file. [No default]
|
||||
* GITWEB_CSS
|
||||
Points to the location where you put gitweb.css on your web server
|
||||
(or to be more generic URI of gitweb stylesheet). Relative to base
|
||||
URI of gitweb. Note that you can setup multiple stylesheets from
|
||||
gitweb config file. [Default: gitweb.css]
|
||||
(or to be more generic, the URI of gitweb stylesheet). Relative to the
|
||||
base URI of gitweb. Note that you can setup multiple stylesheets from
|
||||
the gitweb config file. [Default: gitweb.css]
|
||||
* GITWEB_LOGO
|
||||
Points to the location where you put git-logo.png on your web server
|
||||
(or to be more generic URI of logo, 72x27 size, displayed in top right
|
||||
@@ -100,13 +100,20 @@ You can specify the following configuration variables when building GIT:
|
||||
is set when gitweb.cgi is executed, then the file specified in the
|
||||
environment variable will be loaded instead of the file specified
|
||||
when gitweb.cgi was created. [Default: gitweb_config.perl]
|
||||
* GITWEB_CONFIG_SYSTEM
|
||||
This Perl file will be loaded using 'do' as a fallback if GITWEB_CONFIG
|
||||
does not exist. If the environment variable GITWEB_CONFIG_SYSTEM is set
|
||||
when gitweb.cgi is executed, then the file specified in the environment
|
||||
variable will be loaded instead of the file specified when gitweb.cgi was
|
||||
created. [Default: /etc/gitweb.conf]
|
||||
|
||||
|
||||
Runtime gitweb configuration
|
||||
----------------------------
|
||||
|
||||
You can adjust gitweb behaviour using the file specified in `GITWEB_CONFIG`
|
||||
(defaults to 'gitweb_config.perl' in the same directory as the CGI).
|
||||
(defaults to 'gitweb_config.perl' in the same directory as the CGI), and
|
||||
as a fallback `GITWEB_CONFIG_SYSTEM` (defaults to /etc/gitweb.conf).
|
||||
The most notable thing that is not configurable at compile time are the
|
||||
optional features, stored in the '%features' variable.
|
||||
|
||||
@@ -114,15 +121,15 @@ Ultimate description on how to reconfigure the default features setting
|
||||
in your `GITWEB_CONFIG` or per-project in `project.git/config` can be found
|
||||
as comments inside 'gitweb.cgi'.
|
||||
|
||||
See also "Gitweb config file" (with example of gitweb config file), and
|
||||
"Gitweb repositories" sections in INSTALL file for gitweb.
|
||||
See also the "Gitweb config file" (with an example of config file), and
|
||||
the "Gitweb repositories" sections in INSTALL file for gitweb.
|
||||
|
||||
|
||||
Gitweb config file is [fragment] of perl code. You can set variables
|
||||
The gitweb config file is a fragment of perl code. You can set variables
|
||||
using "our $variable = value"; text from "#" character until the end
|
||||
of a line is ignored. See perlsyn(1) man page for details.
|
||||
|
||||
Below there is list of vaiables which you might want to set in gitweb config.
|
||||
Below is the list of variables which you might want to set in gitweb config.
|
||||
See the top of 'gitweb.cgi' for the full list of variables and their
|
||||
descriptions.
|
||||
|
||||
@@ -133,7 +140,7 @@ You can set, among others, the following variables in gitweb config files
|
||||
(with the exception of $projectroot and $projects_list this list does
|
||||
not include variables usually directly set during build):
|
||||
* $GIT
|
||||
Cure git executable to use. By default set to "$GIT_BINDIR/git", which
|
||||
Core git executable to use. By default set to "$GIT_BINDIR/git", which
|
||||
in turn is by default set to "$(bindir)/git". If you use git from binary
|
||||
package, set this to "/usr/bin/git". This can just be "git" if your
|
||||
webserver has a sensible PATH. If you have multiple git versions
|
||||
@@ -169,7 +176,7 @@ not include variables usually directly set during build):
|
||||
to make it easier to upgrade gitweb. You can add 'site' stylesheet
|
||||
for example by using
|
||||
push @stylesheets, "gitweb-site.css";
|
||||
in gitweb config file.
|
||||
in the gitweb config file.
|
||||
* $logo_url, $logo_label
|
||||
URI and label (title) of GIT logo link (or your site logo, if you choose
|
||||
to use different logo image). By default they point to git homepage;
|
||||
@@ -191,12 +198,12 @@ not include variables usually directly set during build):
|
||||
Default mimetype for blob_plain (raw) view, if mimetype checking
|
||||
doesn't result in some other type; by default 'text/plain'.
|
||||
* $default_text_plain_charset
|
||||
Default charset for text files. If not set, web serwer configuration
|
||||
Default charset for text files. If not set, web server configuration
|
||||
would be used.
|
||||
* $mimetypes_file
|
||||
File to use for (filename extension based) guessing of MIME types before
|
||||
trying /etc/mime.types. Path, if relative, is taken currently as taken
|
||||
relative to current git repositoy.
|
||||
trying /etc/mime.types. Path, if relative, is taken currently as
|
||||
relative to the current git repository.
|
||||
* $fallback_encoding
|
||||
Gitweb assumes this charset if line contains non-UTF-8 characters.
|
||||
Fallback decoding is used without error checking, so it can be even
|
||||
@@ -225,14 +232,14 @@ You can use the following files in repository:
|
||||
single line description of a project (of a repository). Plain text file;
|
||||
HTML will be escaped. By default set to
|
||||
Unnamed repository; edit this file to name it for gitweb.
|
||||
from the template during creating repository. You can use
|
||||
from the template during repository creation. You can use the
|
||||
gitweb.description repo configuration variable, but the file takes
|
||||
precendence.
|
||||
precedence.
|
||||
* cloneurl (or multiple-valued gitweb.url)
|
||||
File with repository URL (used for clone and fetch), one per line.
|
||||
Displayed in the project summary page. You can use multiple-valued
|
||||
gitweb.url repository configuration variable for that, but the file
|
||||
takes precendence.
|
||||
takes precedence.
|
||||
* gitweb.owner
|
||||
You can use the gitweb.owner repository configuration variable to set
|
||||
repository's owner. It is displayed in the project list and summary
|
||||
|
||||
@@ -369,7 +369,12 @@ sub filter_snapshot_fmts {
|
||||
}
|
||||
|
||||
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
|
||||
do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
|
||||
if (-e $GITWEB_CONFIG) {
|
||||
do $GITWEB_CONFIG;
|
||||
} else {
|
||||
our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
|
||||
do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
|
||||
}
|
||||
|
||||
# version of the core git binary
|
||||
our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
|
||||
@@ -506,7 +511,7 @@ sub evaluate_path_info {
|
||||
}
|
||||
# do not change any parameters if an action is given using the query string
|
||||
return if $action;
|
||||
$path_info =~ s,^$project/*,,;
|
||||
$path_info =~ s,^\Q$project\E/*,,;
|
||||
my ($refname, $pathname) = split(/:/, $path_info, 2);
|
||||
if (defined $pathname) {
|
||||
# we got "project.git/branch:filename" or "project.git/branch:dir/"
|
||||
@@ -628,7 +633,7 @@ sub href(%) {
|
||||
my ($use_pathinfo) = gitweb_check_feature('pathinfo');
|
||||
if ($use_pathinfo) {
|
||||
# use PATH_INFO for project name
|
||||
$href .= "/$params{'project'}" if defined $params{'project'};
|
||||
$href .= "/".esc_url($params{'project'}) if defined $params{'project'};
|
||||
delete $params{'project'};
|
||||
|
||||
# Summary just uses the project path URL
|
||||
@@ -2570,7 +2575,7 @@ EOF
|
||||
my $action = $my_uri;
|
||||
my ($use_pathinfo) = gitweb_check_feature('pathinfo');
|
||||
if ($use_pathinfo) {
|
||||
$action .= "/$project";
|
||||
$action .= "/".esc_url($project);
|
||||
} else {
|
||||
$cgi->param("p", $project);
|
||||
}
|
||||
@@ -5171,14 +5176,26 @@ sub git_history {
|
||||
my $refs = git_get_references();
|
||||
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
|
||||
|
||||
my @commitlist = parse_commits($hash_base, 101, (100 * $page),
|
||||
$file_name, "--full-history");
|
||||
if (!@commitlist) {
|
||||
die_error('404 Not Found', "No such file or directory on given branch");
|
||||
}
|
||||
|
||||
if (!defined $hash && defined $file_name) {
|
||||
$hash = git_get_hash_by_path($hash_base, $file_name);
|
||||
# some commits could have deleted file in question,
|
||||
# and not have it in tree, but one of them has to have it
|
||||
for (my $i = 0; $i <= @commitlist; $i++) {
|
||||
$hash = git_get_hash_by_path($commitlist[$i]{'id'}, $file_name);
|
||||
last if defined $hash;
|
||||
}
|
||||
}
|
||||
if (defined $hash) {
|
||||
$ftype = git_get_type($hash);
|
||||
}
|
||||
|
||||
my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history");
|
||||
if (!defined $ftype) {
|
||||
die_error(undef, "Unknown type of object");
|
||||
}
|
||||
|
||||
my $paging_nav = '';
|
||||
if ($page > 0) {
|
||||
|
||||
@@ -1303,8 +1303,11 @@ main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
if (!server.host) {
|
||||
fprintf( stderr, "no imap host specified\n" );
|
||||
return 1;
|
||||
if (!server.tunnel) {
|
||||
fprintf( stderr, "no imap host specified\n" );
|
||||
return 1;
|
||||
}
|
||||
server.host = "tunnel";
|
||||
}
|
||||
|
||||
/* read the messages */
|
||||
|
||||
10
log-tree.c
10
log-tree.c
@@ -249,9 +249,9 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
* not have an empty line between entries.
|
||||
*/
|
||||
extra = "";
|
||||
if (*sep != '\n' && opt->commit_format == CMIT_FMT_ONELINE)
|
||||
if (*sep != '\n' && opt->use_terminator)
|
||||
extra = "\n";
|
||||
if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE)
|
||||
if (opt->shown_one && !opt->use_terminator)
|
||||
putchar(opt->diffopt.line_termination);
|
||||
opt->shown_one = 1;
|
||||
|
||||
@@ -317,8 +317,10 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
if (opt->show_log_size)
|
||||
printf("log size %i\n", (int)msgbuf.len);
|
||||
|
||||
if (msgbuf.len)
|
||||
printf("%s%s%s", msgbuf.buf, extra, sep);
|
||||
if (msgbuf.len) {
|
||||
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
|
||||
printf("%s%s", extra, sep);
|
||||
}
|
||||
strbuf_release(&msgbuf);
|
||||
}
|
||||
|
||||
|
||||
@@ -344,7 +344,7 @@ void usage_with_options_internal(const char * const *usagestr,
|
||||
break;
|
||||
case OPTION_INTEGER:
|
||||
if (opts->flags & PARSE_OPT_OPTARG)
|
||||
pos += fprintf(stderr, " [<n>]");
|
||||
pos += fprintf(stderr, "[<n>]");
|
||||
else
|
||||
pos += fprintf(stderr, " <n>");
|
||||
break;
|
||||
|
||||
34
path.c
34
path.c
@@ -98,7 +98,8 @@ int validate_headref(const char *path)
|
||||
struct stat st;
|
||||
char *buf, buffer[256];
|
||||
unsigned char sha1[20];
|
||||
int len, fd;
|
||||
int fd;
|
||||
ssize_t len;
|
||||
|
||||
if (lstat(path, &st) < 0)
|
||||
return -1;
|
||||
@@ -273,24 +274,25 @@ int adjust_shared_perm(const char *path)
|
||||
if (lstat(path, &st) < 0)
|
||||
return -1;
|
||||
mode = st.st_mode;
|
||||
if (mode & S_IRUSR)
|
||||
mode |= (shared_repository == PERM_GROUP
|
||||
? S_IRGRP
|
||||
: (shared_repository == PERM_EVERYBODY
|
||||
? (S_IRGRP|S_IROTH)
|
||||
: 0));
|
||||
|
||||
if (mode & S_IWUSR)
|
||||
mode |= S_IWGRP;
|
||||
if (shared_repository) {
|
||||
int tweak = shared_repository;
|
||||
if (!(mode & S_IWUSR))
|
||||
tweak &= ~0222;
|
||||
mode = (mode & ~0777) | tweak;
|
||||
} else {
|
||||
/* Preserve old PERM_UMASK behaviour */
|
||||
if (mode & S_IWUSR)
|
||||
mode |= S_IWGRP;
|
||||
}
|
||||
|
||||
if (mode & S_IXUSR)
|
||||
mode |= (shared_repository == PERM_GROUP
|
||||
? S_IXGRP
|
||||
: (shared_repository == PERM_EVERYBODY
|
||||
? (S_IXGRP|S_IXOTH)
|
||||
: 0));
|
||||
if (S_ISDIR(mode))
|
||||
if (S_ISDIR(mode)) {
|
||||
mode |= FORCE_DIR_SET_GID;
|
||||
|
||||
/* Copy read bits to execute bits */
|
||||
mode |= (shared_repository & 0444) >> 2;
|
||||
}
|
||||
|
||||
if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
|
||||
return -2;
|
||||
return 0;
|
||||
|
||||
45
perl/Git.pm
45
perl/Git.pm
@@ -487,22 +487,20 @@ does. In scalar context requires the variable to be set only one time
|
||||
(exception is thrown otherwise), in array context returns allows the
|
||||
variable to be set multiple times and returns all the values.
|
||||
|
||||
Must be called on a repository instance.
|
||||
|
||||
This currently wraps command('config') so it is not so fast.
|
||||
|
||||
=cut
|
||||
|
||||
sub config {
|
||||
my ($self, $var) = @_;
|
||||
$self->repo_path()
|
||||
or throw Error::Simple("not a repository");
|
||||
my ($self, $var) = _maybe_self(@_);
|
||||
|
||||
try {
|
||||
my @cmd = ('config');
|
||||
unshift @cmd, $self if $self;
|
||||
if (wantarray) {
|
||||
return $self->command('config', '--get-all', $var);
|
||||
return command(@cmd, '--get-all', $var);
|
||||
} else {
|
||||
return $self->command_oneline('config', '--get', $var);
|
||||
return command_oneline(@cmd, '--get', $var);
|
||||
}
|
||||
} catch Git::Error::Command with {
|
||||
my $E = shift;
|
||||
@@ -522,20 +520,17 @@ Retrieve the bool configuration C<VARIABLE>. The return value
|
||||
is usable as a boolean in perl (and C<undef> if it's not defined,
|
||||
of course).
|
||||
|
||||
Must be called on a repository instance.
|
||||
|
||||
This currently wraps command('config') so it is not so fast.
|
||||
|
||||
=cut
|
||||
|
||||
sub config_bool {
|
||||
my ($self, $var) = @_;
|
||||
$self->repo_path()
|
||||
or throw Error::Simple("not a repository");
|
||||
my ($self, $var) = _maybe_self(@_);
|
||||
|
||||
try {
|
||||
my $val = $self->command_oneline('config', '--bool', '--get',
|
||||
$var);
|
||||
my @cmd = ('config', '--bool', '--get', $var);
|
||||
unshift @cmd, $self if $self;
|
||||
my $val = command_oneline(@cmd);
|
||||
return undef unless defined $val;
|
||||
return $val eq 'true';
|
||||
} catch Git::Error::Command with {
|
||||
@@ -557,19 +552,17 @@ or 'g' in the config file will cause the value to be multiplied
|
||||
by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
|
||||
It would return C<undef> if configuration variable is not defined,
|
||||
|
||||
Must be called on a repository instance.
|
||||
|
||||
This currently wraps command('config') so it is not so fast.
|
||||
|
||||
=cut
|
||||
|
||||
sub config_int {
|
||||
my ($self, $var) = @_;
|
||||
$self->repo_path()
|
||||
or throw Error::Simple("not a repository");
|
||||
my ($self, $var) = _maybe_self(@_);
|
||||
|
||||
try {
|
||||
return $self->command_oneline('config', '--int', '--get', $var);
|
||||
my @cmd = ('config', '--int', '--get', $var);
|
||||
unshift @cmd, $self if $self;
|
||||
return command_oneline(@cmd);
|
||||
} catch Git::Error::Command with {
|
||||
my $E = shift;
|
||||
if ($E->value() == 1) {
|
||||
@@ -639,15 +632,15 @@ The synopsis is like:
|
||||
"$name <$email>" eq ident_person($name);
|
||||
$time_tz =~ /^\d+ [+-]\d{4}$/;
|
||||
|
||||
Both methods must be called on a repository instance.
|
||||
|
||||
=cut
|
||||
|
||||
sub ident {
|
||||
my ($self, $type) = @_;
|
||||
my ($self, $type) = _maybe_self(@_);
|
||||
my $identstr;
|
||||
if (lc $type eq lc 'committer' or lc $type eq lc 'author') {
|
||||
$identstr = $self->command_oneline('var', 'GIT_'.uc($type).'_IDENT');
|
||||
my @cmd = ('var', 'GIT_'.uc($type).'_IDENT');
|
||||
unshift @cmd, $self if $self;
|
||||
$identstr = command_oneline(@cmd);
|
||||
} else {
|
||||
$identstr = $type;
|
||||
}
|
||||
@@ -659,8 +652,8 @@ sub ident {
|
||||
}
|
||||
|
||||
sub ident_person {
|
||||
my ($self, @ident) = @_;
|
||||
$#ident == 0 and @ident = $self->ident($ident[0]);
|
||||
my ($self, @ident) = _maybe_self(@_);
|
||||
$#ident == 0 and @ident = $self ? $self->ident($ident[0]) : ident($ident[0]);
|
||||
return "$ident[0] <$ident[1]>";
|
||||
}
|
||||
|
||||
|
||||
66
pretty.c
66
pretty.c
@@ -4,40 +4,49 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
|
||||
static struct cmt_fmt_map {
|
||||
const char *n;
|
||||
size_t cmp_len;
|
||||
enum cmit_fmt v;
|
||||
} cmt_fmts[] = {
|
||||
{ "raw", 1, CMIT_FMT_RAW },
|
||||
{ "medium", 1, CMIT_FMT_MEDIUM },
|
||||
{ "short", 1, CMIT_FMT_SHORT },
|
||||
{ "email", 1, CMIT_FMT_EMAIL },
|
||||
{ "full", 5, CMIT_FMT_FULL },
|
||||
{ "fuller", 5, CMIT_FMT_FULLER },
|
||||
{ "oneline", 1, CMIT_FMT_ONELINE },
|
||||
{ "format:", 7, CMIT_FMT_USERFORMAT},
|
||||
};
|
||||
|
||||
static char *user_format;
|
||||
|
||||
enum cmit_fmt get_commit_format(const char *arg)
|
||||
void get_commit_format(const char *arg, struct rev_info *rev)
|
||||
{
|
||||
int i;
|
||||
static struct cmt_fmt_map {
|
||||
const char *n;
|
||||
size_t cmp_len;
|
||||
enum cmit_fmt v;
|
||||
} cmt_fmts[] = {
|
||||
{ "raw", 1, CMIT_FMT_RAW },
|
||||
{ "medium", 1, CMIT_FMT_MEDIUM },
|
||||
{ "short", 1, CMIT_FMT_SHORT },
|
||||
{ "email", 1, CMIT_FMT_EMAIL },
|
||||
{ "full", 5, CMIT_FMT_FULL },
|
||||
{ "fuller", 5, CMIT_FMT_FULLER },
|
||||
{ "oneline", 1, CMIT_FMT_ONELINE },
|
||||
};
|
||||
|
||||
if (!arg || !*arg)
|
||||
return CMIT_FMT_DEFAULT;
|
||||
rev->use_terminator = 0;
|
||||
if (!arg || !*arg) {
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
return;
|
||||
}
|
||||
if (*arg == '=')
|
||||
arg++;
|
||||
if (!prefixcmp(arg, "format:")) {
|
||||
if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
|
||||
const char *cp = strchr(arg, ':') + 1;
|
||||
free(user_format);
|
||||
user_format = xstrdup(arg + 7);
|
||||
return CMIT_FMT_USERFORMAT;
|
||||
user_format = xstrdup(cp);
|
||||
if (arg[0] == 't')
|
||||
rev->use_terminator = 1;
|
||||
rev->commit_format = CMIT_FMT_USERFORMAT;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
|
||||
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
|
||||
!strncmp(arg, cmt_fmts[i].n, strlen(arg)))
|
||||
return cmt_fmts[i].v;
|
||||
!strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
|
||||
if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
|
||||
rev->use_terminator = 1;
|
||||
rev->commit_format = cmt_fmts[i].v;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
die("invalid --pretty format: %s", arg);
|
||||
@@ -457,6 +466,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
const struct commit *commit = c->commit;
|
||||
const char *msg = commit->buffer;
|
||||
struct commit_list *p;
|
||||
int h1, h2;
|
||||
|
||||
/* these are independent of the commit */
|
||||
switch (placeholder[0]) {
|
||||
@@ -478,6 +488,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
case 'n': /* newline */
|
||||
strbuf_addch(sb, '\n');
|
||||
return 1;
|
||||
case 'x':
|
||||
/* %x00 == NUL, %x0a == LF, etc. */
|
||||
if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
|
||||
h1 <= 16 &&
|
||||
0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
|
||||
h2 <= 16) {
|
||||
strbuf_addch(sb, (h1<<4)|h2);
|
||||
return 3;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* these depend on the commit */
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||
|
||||
static int deny_non_fast_forwards = 0;
|
||||
static int receive_fsck_objects;
|
||||
static int receive_unpack_limit = -1;
|
||||
static int transfer_unpack_limit = -1;
|
||||
static int unpack_limit = 100;
|
||||
@@ -35,6 +36,11 @@ static int receive_pack_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(var, "receive.fsckobjects") == 0) {
|
||||
receive_fsck_objects = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
@@ -368,11 +374,13 @@ static const char *unpack(void)
|
||||
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
|
||||
|
||||
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
||||
int code;
|
||||
const char *unpacker[3];
|
||||
unpacker[0] = "unpack-objects";
|
||||
unpacker[1] = hdr_arg;
|
||||
unpacker[2] = NULL;
|
||||
int code, i = 0;
|
||||
const char *unpacker[4];
|
||||
unpacker[i++] = "unpack-objects";
|
||||
if (receive_fsck_objects)
|
||||
unpacker[i++] = "--strict";
|
||||
unpacker[i++] = hdr_arg;
|
||||
unpacker[i++] = NULL;
|
||||
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
|
||||
switch (code) {
|
||||
case 0:
|
||||
@@ -393,8 +401,8 @@ static const char *unpack(void)
|
||||
return "unpacker exited with error code";
|
||||
}
|
||||
} else {
|
||||
const char *keeper[6];
|
||||
int s, status;
|
||||
const char *keeper[7];
|
||||
int s, status, i = 0;
|
||||
char keep_arg[256];
|
||||
struct child_process ip;
|
||||
|
||||
@@ -402,12 +410,14 @@ static const char *unpack(void)
|
||||
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
||||
strcpy(keep_arg + s, "localhost");
|
||||
|
||||
keeper[0] = "index-pack";
|
||||
keeper[1] = "--stdin";
|
||||
keeper[2] = "--fix-thin";
|
||||
keeper[3] = hdr_arg;
|
||||
keeper[4] = keep_arg;
|
||||
keeper[5] = NULL;
|
||||
keeper[i++] = "index-pack";
|
||||
keeper[i++] = "--stdin";
|
||||
if (receive_fsck_objects)
|
||||
keeper[i++] = "--strict";
|
||||
keeper[i++] = "--fix-thin";
|
||||
keeper[i++] = hdr_arg;
|
||||
keeper[i++] = keep_arg;
|
||||
keeper[i++] = NULL;
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
ip.argv = keeper;
|
||||
ip.out = -1;
|
||||
|
||||
3
refs.c
3
refs.c
@@ -368,7 +368,8 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re
|
||||
|
||||
const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
|
||||
{
|
||||
int depth = MAXDEPTH, len;
|
||||
int depth = MAXDEPTH;
|
||||
ssize_t len;
|
||||
char buffer[256];
|
||||
static char ref_buffer[256];
|
||||
|
||||
|
||||
55
remote.c
55
remote.c
@@ -315,7 +315,7 @@ static int handle_config(const char *key, const char *value)
|
||||
}
|
||||
if (!prefixcmp(key, "url.")) {
|
||||
struct rewrite *rewrite;
|
||||
name = key + 5;
|
||||
name = key + 4;
|
||||
subkey = strrchr(name, '.');
|
||||
if (!subkey)
|
||||
return 0;
|
||||
@@ -409,7 +409,7 @@ static void read_config(void)
|
||||
alias_all_urls();
|
||||
}
|
||||
|
||||
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch)
|
||||
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
|
||||
{
|
||||
int i;
|
||||
int st;
|
||||
@@ -519,17 +519,32 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
return rs;
|
||||
|
||||
invalid:
|
||||
if (verify) {
|
||||
free(rs);
|
||||
return NULL;
|
||||
}
|
||||
die("Invalid refspec '%s'", refspec[i]);
|
||||
}
|
||||
|
||||
int valid_fetch_refspec(const char *fetch_refspec_str)
|
||||
{
|
||||
const char *fetch_refspec[] = { fetch_refspec_str };
|
||||
struct refspec *refspec;
|
||||
|
||||
refspec = parse_refspec_internal(1, fetch_refspec, 1, 1);
|
||||
if (refspec)
|
||||
free(refspec);
|
||||
return !!refspec;
|
||||
}
|
||||
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
|
||||
{
|
||||
return parse_refspec_internal(nr_refspec, refspec, 1);
|
||||
return parse_refspec_internal(nr_refspec, refspec, 1, 0);
|
||||
}
|
||||
|
||||
struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
|
||||
{
|
||||
return parse_refspec_internal(nr_refspec, refspec, 0);
|
||||
return parse_refspec_internal(nr_refspec, refspec, 0, 0);
|
||||
}
|
||||
|
||||
static int valid_remote_nick(const char *name)
|
||||
@@ -797,6 +812,26 @@ static struct ref *make_linked_ref(const char *name, struct ref ***tail)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *guess_ref(const char *name, struct ref *peer)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
unsigned char sha1[20];
|
||||
|
||||
const char *r = resolve_ref(peer->name, sha1, 1, NULL);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
if (!prefixcmp(r, "refs/heads/"))
|
||||
strbuf_addstr(&buf, "refs/heads/");
|
||||
else if (!prefixcmp(r, "refs/tags/"))
|
||||
strbuf_addstr(&buf, "refs/tags/");
|
||||
else
|
||||
return NULL;
|
||||
|
||||
strbuf_addstr(&buf, name);
|
||||
return strbuf_detach(&buf, NULL);
|
||||
}
|
||||
|
||||
static int match_explicit(struct ref *src, struct ref *dst,
|
||||
struct ref ***dst_tail,
|
||||
struct refspec *rs,
|
||||
@@ -805,6 +840,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
|
||||
struct ref *matched_src, *matched_dst;
|
||||
|
||||
const char *dst_value = rs->dst;
|
||||
char *dst_guess;
|
||||
|
||||
if (rs->pattern)
|
||||
return errs;
|
||||
@@ -851,10 +887,15 @@ static int match_explicit(struct ref *src, struct ref *dst,
|
||||
case 0:
|
||||
if (!memcmp(dst_value, "refs/", 5))
|
||||
matched_dst = make_linked_ref(dst_value, dst_tail);
|
||||
else if((dst_guess = guess_ref(dst_value, matched_src)))
|
||||
matched_dst = make_linked_ref(dst_guess, dst_tail);
|
||||
else
|
||||
error("dst refspec %s does not match any "
|
||||
"existing ref on the remote and does "
|
||||
"not start with refs/.", dst_value);
|
||||
error("unable to push to unqualified destination: %s\n"
|
||||
"The destination refspec neither matches an "
|
||||
"existing ref on the remote nor\n"
|
||||
"begins with refs/, and we are unable to "
|
||||
"guess a prefix based on the source ref.",
|
||||
dst_value);
|
||||
break;
|
||||
default:
|
||||
matched_dst = NULL;
|
||||
|
||||
1
remote.h
1
remote.h
@@ -67,6 +67,7 @@ void free_refs(struct ref *ref);
|
||||
*/
|
||||
void ref_remove_duplicates(struct ref *ref_map);
|
||||
|
||||
int valid_fetch_refspec(const char *refspec);
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
|
||||
struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
|
||||
|
||||
|
||||
@@ -1083,6 +1083,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--topo-order")) {
|
||||
revs->lifo = 1;
|
||||
revs->topo_order = 1;
|
||||
continue;
|
||||
}
|
||||
@@ -1198,7 +1199,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
}
|
||||
if (!prefixcmp(arg, "--pretty")) {
|
||||
revs->verbose_header = 1;
|
||||
revs->commit_format = get_commit_format(arg+8);
|
||||
get_commit_format(arg+8, revs);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--root")) {
|
||||
|
||||
@@ -64,7 +64,8 @@ struct rev_info {
|
||||
|
||||
/* Format info */
|
||||
unsigned int shown_one:1,
|
||||
abbrev_commit:1;
|
||||
abbrev_commit:1,
|
||||
use_terminator:1;
|
||||
enum date_mode date_mode;
|
||||
|
||||
const char **ignore_packed; /* pretend objects in these are unpacked */
|
||||
|
||||
60
setup.c
60
setup.c
@@ -448,21 +448,53 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
|
||||
int git_config_perm(const char *var, const char *value)
|
||||
{
|
||||
if (value) {
|
||||
int i;
|
||||
if (!strcmp(value, "umask"))
|
||||
return PERM_UMASK;
|
||||
if (!strcmp(value, "group"))
|
||||
return PERM_GROUP;
|
||||
if (!strcmp(value, "all") ||
|
||||
!strcmp(value, "world") ||
|
||||
!strcmp(value, "everybody"))
|
||||
return PERM_EVERYBODY;
|
||||
i = atoi(value);
|
||||
if (i > 1)
|
||||
return i;
|
||||
int i;
|
||||
char *endptr;
|
||||
|
||||
if (value == NULL)
|
||||
return PERM_GROUP;
|
||||
|
||||
if (!strcmp(value, "umask"))
|
||||
return PERM_UMASK;
|
||||
if (!strcmp(value, "group"))
|
||||
return PERM_GROUP;
|
||||
if (!strcmp(value, "all") ||
|
||||
!strcmp(value, "world") ||
|
||||
!strcmp(value, "everybody"))
|
||||
return PERM_EVERYBODY;
|
||||
|
||||
/* Parse octal numbers */
|
||||
i = strtol(value, &endptr, 8);
|
||||
|
||||
/* If not an octal number, maybe true/false? */
|
||||
if (*endptr != 0)
|
||||
return git_config_bool(var, value) ? PERM_GROUP : PERM_UMASK;
|
||||
|
||||
/*
|
||||
* Treat values 0, 1 and 2 as compatibility cases, otherwise it is
|
||||
* a chmod value.
|
||||
*/
|
||||
switch (i) {
|
||||
case PERM_UMASK: /* 0 */
|
||||
return PERM_UMASK;
|
||||
case OLD_PERM_GROUP: /* 1 */
|
||||
return PERM_GROUP;
|
||||
case OLD_PERM_EVERYBODY: /* 2 */
|
||||
return PERM_EVERYBODY;
|
||||
}
|
||||
return git_config_bool(var, value);
|
||||
|
||||
/* A filemode value was given: 0xxx */
|
||||
|
||||
if ((i & 0600) != 0600)
|
||||
die("Problem with core.sharedRepository filemode value "
|
||||
"(0%.3o).\nThe owner of files must always have "
|
||||
"read and write permissions.", i);
|
||||
|
||||
/*
|
||||
* Mask filemode value. Others can not get write permission.
|
||||
* x flags for directories are handled separately.
|
||||
*/
|
||||
return i & 0666;
|
||||
}
|
||||
|
||||
int check_repository_format_version(const char *var, const char *value)
|
||||
|
||||
171
sha1-lookup.c
Normal file
171
sha1-lookup.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "cache.h"
|
||||
#include "sha1-lookup.h"
|
||||
|
||||
/*
|
||||
* Conventional binary search loop looks like this:
|
||||
*
|
||||
* unsigned lo, hi;
|
||||
* do {
|
||||
* unsigned mi = (lo + hi) / 2;
|
||||
* int cmp = "entry pointed at by mi" minus "target";
|
||||
* if (!cmp)
|
||||
* return (mi is the wanted one)
|
||||
* if (cmp > 0)
|
||||
* hi = mi; "mi is larger than target"
|
||||
* else
|
||||
* lo = mi+1; "mi is smaller than target"
|
||||
* } while (lo < hi);
|
||||
*
|
||||
* The invariants are:
|
||||
*
|
||||
* - When entering the loop, lo points at a slot that is never
|
||||
* above the target (it could be at the target), hi points at a
|
||||
* slot that is guaranteed to be above the target (it can never
|
||||
* be at the target).
|
||||
*
|
||||
* - We find a point 'mi' between lo and hi (mi could be the same
|
||||
* as lo, but never can be as same as hi), and check if it hits
|
||||
* the target. There are three cases:
|
||||
*
|
||||
* - if it is a hit, we are happy.
|
||||
*
|
||||
* - if it is strictly higher than the target, we set it to hi,
|
||||
* and repeat the search.
|
||||
*
|
||||
* - if it is strictly lower than the target, we update lo to
|
||||
* one slot after it, because we allow lo to be at the target.
|
||||
*
|
||||
* If the loop exits, there is no matching entry.
|
||||
*
|
||||
* When choosing 'mi', we do not have to take the "middle" but
|
||||
* anywhere in between lo and hi, as long as lo <= mi < hi is
|
||||
* satisfied. When we somehow know that the distance between the
|
||||
* target and lo is much shorter than the target and hi, we could
|
||||
* pick mi that is much closer to lo than the midway.
|
||||
*
|
||||
* Now, we can take advantage of the fact that SHA-1 is a good hash
|
||||
* function, and as long as there are enough entries in the table, we
|
||||
* can expect uniform distribution. An entry that begins with for
|
||||
* example "deadbeef..." is much likely to appear much later than in
|
||||
* the midway of the table. It can reasonably be expected to be near
|
||||
* 87% (222/256) from the top of the table.
|
||||
*
|
||||
* However, we do not want to pick "mi" too precisely. If the entry at
|
||||
* the 87% in the above example turns out to be higher than the target
|
||||
* we are looking for, we would end up narrowing the search space down
|
||||
* only by 13%, instead of 50% we would get if we did a simple binary
|
||||
* search. So we would want to hedge our bets by being less aggressive.
|
||||
*
|
||||
* The table at "table" holds at least "nr" entries of "elem_size"
|
||||
* bytes each. Each entry has the SHA-1 key at "key_offset". The
|
||||
* table is sorted by the SHA-1 key of the entries. The caller wants
|
||||
* to find the entry with "key", and knows that the entry at "lo" is
|
||||
* not higher than the entry it is looking for, and that the entry at
|
||||
* "hi" is higher than the entry it is looking for.
|
||||
*/
|
||||
int sha1_entry_pos(const void *table,
|
||||
size_t elem_size,
|
||||
size_t key_offset,
|
||||
unsigned lo, unsigned hi, unsigned nr,
|
||||
const unsigned char *key)
|
||||
{
|
||||
const unsigned char *base = table;
|
||||
const unsigned char *hi_key, *lo_key;
|
||||
unsigned ofs_0;
|
||||
static int debug_lookup = -1;
|
||||
|
||||
if (debug_lookup < 0)
|
||||
debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
|
||||
|
||||
if (!nr || lo >= hi)
|
||||
return -1;
|
||||
|
||||
if (nr == hi)
|
||||
hi_key = NULL;
|
||||
else
|
||||
hi_key = base + elem_size * hi + key_offset;
|
||||
lo_key = base + elem_size * lo + key_offset;
|
||||
|
||||
ofs_0 = 0;
|
||||
do {
|
||||
int cmp;
|
||||
unsigned ofs, mi, range;
|
||||
unsigned lov, hiv, kyv;
|
||||
const unsigned char *mi_key;
|
||||
|
||||
range = hi - lo;
|
||||
if (hi_key) {
|
||||
for (ofs = ofs_0; ofs < 20; ofs++)
|
||||
if (lo_key[ofs] != hi_key[ofs])
|
||||
break;
|
||||
ofs_0 = ofs;
|
||||
/*
|
||||
* byte 0 thru (ofs-1) are the same between
|
||||
* lo and hi; ofs is the first byte that is
|
||||
* different.
|
||||
*/
|
||||
hiv = hi_key[ofs_0];
|
||||
if (ofs_0 < 19)
|
||||
hiv = (hiv << 8) | hi_key[ofs_0+1];
|
||||
} else {
|
||||
hiv = 256;
|
||||
if (ofs_0 < 19)
|
||||
hiv <<= 8;
|
||||
}
|
||||
lov = lo_key[ofs_0];
|
||||
kyv = key[ofs_0];
|
||||
if (ofs_0 < 19) {
|
||||
lov = (lov << 8) | lo_key[ofs_0+1];
|
||||
kyv = (kyv << 8) | key[ofs_0+1];
|
||||
}
|
||||
assert(lov < hiv);
|
||||
|
||||
if (kyv < lov)
|
||||
return -1 - lo;
|
||||
if (hiv < kyv)
|
||||
return -1 - hi;
|
||||
|
||||
/*
|
||||
* Even if we know the target is much closer to 'hi'
|
||||
* than 'lo', if we pick too precisely and overshoot
|
||||
* (e.g. when we know 'mi' is closer to 'hi' than to
|
||||
* 'lo', pick 'mi' that is higher than the target), we
|
||||
* end up narrowing the search space by a smaller
|
||||
* amount (i.e. the distance between 'mi' and 'hi')
|
||||
* than what we would have (i.e. about half of 'lo'
|
||||
* and 'hi'). Hedge our bets to pick 'mi' less
|
||||
* aggressively, i.e. make 'mi' a bit closer to the
|
||||
* middle than we would otherwise pick.
|
||||
*/
|
||||
kyv = (kyv * 6 + lov + hiv) / 8;
|
||||
if (lov < hiv - 1) {
|
||||
if (kyv == lov)
|
||||
kyv++;
|
||||
else if (kyv == hiv)
|
||||
kyv--;
|
||||
}
|
||||
mi = (range - 1) * (kyv - lov) / (hiv - lov) + lo;
|
||||
|
||||
if (debug_lookup) {
|
||||
printf("lo %u hi %u rg %u mi %u ", lo, hi, range, mi);
|
||||
printf("ofs %u lov %x, hiv %x, kyv %x\n",
|
||||
ofs_0, lov, hiv, kyv);
|
||||
}
|
||||
if (!(lo <= mi && mi < hi))
|
||||
die("assertion failure lo %u mi %u hi %u %s",
|
||||
lo, mi, hi, sha1_to_hex(key));
|
||||
|
||||
mi_key = base + elem_size * mi + key_offset;
|
||||
cmp = memcmp(mi_key + ofs_0, key + ofs_0, 20 - ofs_0);
|
||||
if (!cmp)
|
||||
return mi;
|
||||
if (cmp > 0) {
|
||||
hi = mi;
|
||||
hi_key = mi_key;
|
||||
} else {
|
||||
lo = mi + 1;
|
||||
lo_key = mi_key + elem_size;
|
||||
}
|
||||
} while (lo < hi);
|
||||
return -lo-1;
|
||||
}
|
||||
9
sha1-lookup.h
Normal file
9
sha1-lookup.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef SHA1_LOOKUP_H
|
||||
#define SHA1_LOOKUP_H
|
||||
|
||||
extern int sha1_entry_pos(const void *table,
|
||||
size_t elem_size,
|
||||
size_t key_offset,
|
||||
unsigned lo, unsigned hi, unsigned nr,
|
||||
const unsigned char *key);
|
||||
#endif
|
||||
35
sha1_file.c
35
sha1_file.c
@@ -15,6 +15,7 @@
|
||||
#include "tree.h"
|
||||
#include "refs.h"
|
||||
#include "pack-revindex.h"
|
||||
#include "sha1-lookup.h"
|
||||
|
||||
#ifndef O_NOATIME
|
||||
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
|
||||
@@ -1679,7 +1680,12 @@ off_t find_pack_entry_one(const unsigned char *sha1,
|
||||
{
|
||||
const uint32_t *level1_ofs = p->index_data;
|
||||
const unsigned char *index = p->index_data;
|
||||
unsigned hi, lo;
|
||||
unsigned hi, lo, stride;
|
||||
static int use_lookup = -1;
|
||||
static int debug_lookup = -1;
|
||||
|
||||
if (debug_lookup < 0)
|
||||
debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
|
||||
|
||||
if (!index) {
|
||||
if (open_pack_index(p))
|
||||
@@ -1694,11 +1700,34 @@ off_t find_pack_entry_one(const unsigned char *sha1,
|
||||
index += 4 * 256;
|
||||
hi = ntohl(level1_ofs[*sha1]);
|
||||
lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
|
||||
if (p->index_version > 1) {
|
||||
stride = 20;
|
||||
} else {
|
||||
stride = 24;
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if (debug_lookup)
|
||||
printf("%02x%02x%02x... lo %u hi %u nr %u\n",
|
||||
sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
|
||||
|
||||
if (use_lookup < 0)
|
||||
use_lookup = !!getenv("GIT_USE_LOOKUP");
|
||||
if (use_lookup) {
|
||||
int pos = sha1_entry_pos(index, stride, 0,
|
||||
lo, hi, p->num_objects, sha1);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
return nth_packed_object_offset(p, pos);
|
||||
}
|
||||
|
||||
do {
|
||||
unsigned mi = (lo + hi) / 2;
|
||||
unsigned x = (p->index_version > 1) ? (mi * 20) : (mi * 24 + 4);
|
||||
int cmp = hashcmp(index + x, sha1);
|
||||
int cmp = hashcmp(index + mi * stride, sha1);
|
||||
|
||||
if (debug_lookup)
|
||||
printf("lo %u hi %u rg %u mi %u\n",
|
||||
lo, hi, hi - lo, mi);
|
||||
if (!cmp)
|
||||
return nth_packed_object_offset(p, mi);
|
||||
if (cmp > 0)
|
||||
|
||||
@@ -351,8 +351,11 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
}
|
||||
if (0 <= nth)
|
||||
at_time = 0;
|
||||
else
|
||||
at_time = approxidate(str + at + 2);
|
||||
else {
|
||||
char *tmp = xstrndup(str + at + 2, reflog_len);
|
||||
at_time = approxidate(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
if (read_ref_at(real_ref, at_time, nth, sha1, NULL,
|
||||
&co_time, &co_tz, &co_cnt)) {
|
||||
if (at_time)
|
||||
|
||||
@@ -21,6 +21,7 @@ test_expect_success 'setup' '
|
||||
mkdir -p a/b/d a/c &&
|
||||
(
|
||||
echo "f test=f"
|
||||
echo "a/i test=a/i"
|
||||
) >.gitattributes &&
|
||||
(
|
||||
echo "g test=a/g" &&
|
||||
@@ -46,4 +47,11 @@ test_expect_success 'attribute test' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'root subdir attribute test' '
|
||||
|
||||
attr_check a/i a/i &&
|
||||
attr_check subdir/a/i unspecified
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user