mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge GIT v1.5.2-rc1
This commit is contained in:
1
.mailmap
1
.mailmap
@@ -23,6 +23,7 @@ Lars Doelle <lars.doelle@on-line.de>
|
||||
Lars Doelle <lars.doelle@on-line ! de>
|
||||
Lukas Sandström <lukass@etek.chalmers.se>
|
||||
Martin Langhoff <martin@catalyst.net.nz>
|
||||
Michele Ballabio <barra_cuda@katamail.com>
|
||||
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
|
||||
Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
|
||||
René Scharfe <rene.scharfe@lsrfire.ath.cx>
|
||||
|
||||
46
Documentation/RelNotes-1.5.1.3.txt
Normal file
46
Documentation/RelNotes-1.5.1.3.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
GIT v1.5.1.3 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.1.2
|
||||
--------------------
|
||||
|
||||
* Bugfixes
|
||||
|
||||
- git-add tried to optimize by finding common leading
|
||||
directories across its arguments but botched, causing very
|
||||
confused behaviour.
|
||||
|
||||
- unofficial rpm.spec file shipped with git was letting
|
||||
ETC_GITCONFIG set to /usr/etc/gitconfig. Tweak the official
|
||||
Makefile to make it harder for distro people to make the
|
||||
same mistake, by setting the variable to /etc/gitconfig if
|
||||
prefix is set to /usr.
|
||||
|
||||
- git-svn inconsistently stripped away username from the URL
|
||||
only when svnsync_props was in use.
|
||||
|
||||
- git-svn got confused when handling symlinks on Mac OS.
|
||||
|
||||
- git-send-email was not quoting recipient names that have
|
||||
period '.' in them. Also it did not allow overriding
|
||||
envelope sender, which made it impossible to send patches to
|
||||
certain subscriber-only lists.
|
||||
|
||||
- built-in write_tree() routine had a sequence that renamed a
|
||||
file that is still open, which some systems did not like.
|
||||
|
||||
- when memory is very tight, sliding mmap code to read
|
||||
packfiles incorrectly closed the fd that was still being
|
||||
used to read the pack.
|
||||
|
||||
- import-tars contributed front-end for fastimport was passing
|
||||
wrong directory modes without checking.
|
||||
|
||||
- git-fastimport trusted its input too much and allowed to
|
||||
create corrupt tree objects with entries without a name.
|
||||
|
||||
- git-fetch needlessly barfed when too long reflog action
|
||||
description was given by the caller.
|
||||
|
||||
Also contains various documentation updates.
|
||||
|
||||
@@ -26,8 +26,14 @@ Updates since v1.5.1
|
||||
considered a binary or text (the former would be treated by
|
||||
'git diff' not to produce textual output; the latter can go
|
||||
through the line endings conversion process in repositories
|
||||
with core.autocrlf set), and specify a custom 3-way merge
|
||||
driver.
|
||||
with core.autocrlf set), expand and unexpand '$ident$' keyword
|
||||
with blob object name, specify a custom 3-way merge driver,
|
||||
and specify a custom diff driver. You can also apply
|
||||
arbitrary filter to contents on check-in/check-out codepath
|
||||
but this feature is an extremely sharp-edged razor and needs
|
||||
to be handled with caution (do not use it unless you
|
||||
understand the earlier mailing list discussion on keyward
|
||||
expansion).
|
||||
|
||||
* The packfile format now optionally suports 64-bit index.
|
||||
|
||||
@@ -53,8 +59,21 @@ Updates since v1.5.1
|
||||
commit -a" (i.e. update the index to match the working
|
||||
tree); it obviously does not make a commit.
|
||||
|
||||
- "git clean" honors a new configuration, "clean.requireforce". When
|
||||
set to true, this makes "git clean" a no-op, preventing you
|
||||
from losing files by typing "git clean" when you meant to
|
||||
say "make clean". You can still say "git clean -f" to
|
||||
override this.
|
||||
|
||||
- "git log" family of commands learned --date={local,relative,default}
|
||||
option. --date=relative is synonym to the --relative-date.
|
||||
--date=local gives the timestamp in local timezone.
|
||||
|
||||
* Updated behavior of existing commands.
|
||||
|
||||
- When $GIT_COMMITTER_EMAIL or $GIT_AUTHOR_EMAIL is not set
|
||||
but $EMAIL is set, the latter is used as a substitute.
|
||||
|
||||
- "git diff --stat" shows size of preimage and postimage blobs
|
||||
for binary contents. Earlier it only said "Bin".
|
||||
|
||||
@@ -82,11 +101,17 @@ Updates since v1.5.1
|
||||
- "gitview" (in contrib/ section) learned to better support
|
||||
"git-annotate".
|
||||
|
||||
- "git diff $commit1:$path2 $commit2:$path2" can now report
|
||||
mode changes between the two blobs.
|
||||
|
||||
- Local "git fetch" from a repository whose object store is
|
||||
one of the alternates (e.g. fetching from the origin in a
|
||||
repository created with "git clone -l -s") avoids
|
||||
downloading objects unnecessary.
|
||||
|
||||
- "git blame" uses .mailmap to canonicalize the author name
|
||||
just like "git shortlog" does.
|
||||
|
||||
* Builds
|
||||
|
||||
- git-p4import has never been installed; now there is an
|
||||
@@ -102,11 +127,15 @@ Updates since v1.5.1
|
||||
|
||||
* Performance Tweaks
|
||||
|
||||
- optimized "git-rev-list --bisect" (hence "git-bisect").
|
||||
- Optimized "git-rev-list --bisect" (hence "git-bisect").
|
||||
|
||||
- optimized "git-add $path" in a large directory, most of
|
||||
- Optimized "git-add $path" in a large directory, most of
|
||||
whose contents are ignored.
|
||||
|
||||
- The recursive merge strategy updated a worktree file that
|
||||
was changed identically in two branches, when one of them
|
||||
renamed it. We do not do that when there is no rename, so
|
||||
match that behaviour.
|
||||
|
||||
Fixes since v1.5.1
|
||||
------------------
|
||||
@@ -133,12 +162,15 @@ this release, unless otherwise noted.
|
||||
will not be backported to 1.5.1.x series, as it is rather an
|
||||
intrusive change.
|
||||
|
||||
- git-fetch had trouble with a remote with insanely large number
|
||||
of refs.
|
||||
|
||||
* Documentation updates
|
||||
|
||||
* Performance Tweaks
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.1.2-242-g2d76548
|
||||
O=v1.5.2-rc0-106-g07c785d
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
Checklist (and a short version for the impatient):
|
||||
|
||||
Commits:
|
||||
|
||||
- make commits of logical units
|
||||
- check for unnecessary whitespace with "git diff --check"
|
||||
before committing
|
||||
@@ -12,8 +14,14 @@ Checklist (and a short version for the impatient):
|
||||
commit message (or just use the option "-s" when
|
||||
committing) to confirm that you agree to the Developer's
|
||||
Certificate of Origin
|
||||
- do not PGP sign your patch
|
||||
|
||||
Patch:
|
||||
|
||||
- use "git format-patch -M" to create the patch
|
||||
- send your patch to <git@vger.kernel.org>. If you use
|
||||
git-send-email(1), please test it first by sending
|
||||
email to yourself.
|
||||
- do not PGP sign your patch
|
||||
- do not attach your patch, but read in the mail
|
||||
body, unless you cannot teach your mailer to
|
||||
leave the formatting of the patch alone.
|
||||
|
||||
@@ -9,8 +9,28 @@
|
||||
--show-stats::
|
||||
Include additional statistics at the end of blame output.
|
||||
|
||||
-L n,m::
|
||||
Annotate only the specified line range (lines count from 1).
|
||||
-L <start>,<end>::
|
||||
Annotate only the given line range. <start> and <end> can take
|
||||
one of these forms:
|
||||
|
||||
- number
|
||||
+
|
||||
If <start> or <end> is a number, it specifies an
|
||||
absolute line number (lines count from 1).
|
||||
+
|
||||
|
||||
- /regex/
|
||||
+
|
||||
This form will use the first line matching the given
|
||||
POSIX regex. If <end> is a regex, it will search
|
||||
starting at the line given by <start>.
|
||||
+
|
||||
|
||||
- +offset or -offset
|
||||
+
|
||||
This is only valid for <end> and will specify a number
|
||||
of lines before or after the line given by <start>.
|
||||
+
|
||||
|
||||
-l::
|
||||
Show long rev (Default: off).
|
||||
|
||||
@@ -610,8 +610,8 @@ tar.umask::
|
||||
|
||||
user.email::
|
||||
Your email address to be recorded in any newly created commits.
|
||||
Can be overridden by the 'GIT_AUTHOR_EMAIL' and 'GIT_COMMITTER_EMAIL'
|
||||
environment variables. See gitlink:git-commit-tree[1].
|
||||
Can be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and
|
||||
'EMAIL' environment variables. See gitlink:git-commit-tree[1].
|
||||
|
||||
user.name::
|
||||
Your full name to be recorded in any newly created commits.
|
||||
|
||||
@@ -319,10 +319,9 @@ argument to `git-commit-tree`.
|
||||
`git-commit-tree` normally takes several arguments -- it wants to know
|
||||
what the 'parent' of a commit was, but since this is the first commit
|
||||
ever in this new repository, and it has no parents, we only need to pass in
|
||||
the object name of the tree. However, `git-commit-tree`
|
||||
also wants to get a commit message
|
||||
on its standard input, and it will write out the resulting object name for the
|
||||
commit to its standard output.
|
||||
the object name of the tree. However, `git-commit-tree` also wants to get a
|
||||
commit message on its standard input, and it will write out the resulting
|
||||
object name for the commit to its standard output.
|
||||
|
||||
And this is where we create the `.git/refs/heads/master` file
|
||||
which is pointed at by `HEAD`. This file is supposed to contain
|
||||
@@ -1304,7 +1303,7 @@ So, we can use somebody else's work from a remote repository, but
|
||||
how can *you* prepare a repository to let other people pull from
|
||||
it?
|
||||
|
||||
Your do your real work in your working tree that has your
|
||||
You do your real work in your working tree that has your
|
||||
primary repository hanging under it as its `.git` subdirectory.
|
||||
You *could* make that repository accessible remotely and ask
|
||||
people to pull from it, but in practice that is not the way
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
-q, \--quiet::
|
||||
Pass --quiet to git-fetch-pack and silence any other internally
|
||||
used programs.
|
||||
|
||||
-v, \--verbose::
|
||||
Be verbose.
|
||||
|
||||
-a, \--append::
|
||||
Append ref names and object names of fetched refs to the
|
||||
existing contents of `.git/FETCH_HEAD`. Without this
|
||||
option old data in `.git/FETCH_HEAD` will be overwritten.
|
||||
|
||||
\--upload-pack <upload-pack>::
|
||||
When given, and the repository to fetch from is handled
|
||||
by 'git-fetch-pack', '--exec=<upload-pack>' is passed to
|
||||
the command to specify non-default path for the command
|
||||
run on the other end.
|
||||
When given, and the repository to fetch from is handled
|
||||
by 'git-fetch-pack', '--exec=<upload-pack>' is passed to
|
||||
the command to specify non-default path for the command
|
||||
run on the other end.
|
||||
|
||||
-f, \--force::
|
||||
When `git-fetch` is used with `<rbranch>:<lbranch>`
|
||||
@@ -16,7 +23,7 @@
|
||||
fetches is a descendant of `<lbranch>`. This option
|
||||
overrides that check.
|
||||
|
||||
\--no-tags::
|
||||
-n, \--no-tags::
|
||||
By default, `git-fetch` fetches tags that point at
|
||||
objects that are downloaded from the remote repository
|
||||
and stores them locally. This option disables this
|
||||
|
||||
@@ -8,7 +8,7 @@ git-blame - Show what revision and author last modified each line of a file
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-blame' [-c] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m]
|
||||
'git-blame' [-c] [-b] [--root] [-s] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m]
|
||||
[-S <revs-file>] [-M] [-C] [-C] [--since=<date>]
|
||||
[<rev> | --contents <file>] [--] <file>
|
||||
|
||||
@@ -60,6 +60,9 @@ include::blame-options.txt[]
|
||||
-n, --show-number::
|
||||
Show line number in the original commit (Default: off).
|
||||
|
||||
-s::
|
||||
Suppress author name and timestamp from the output.
|
||||
|
||||
THE PORCELAIN FORMAT
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -60,6 +60,8 @@ either `.git/config` file, or using the following environment variables.
|
||||
GIT_AUTHOR_DATE
|
||||
GIT_COMMITTER_NAME
|
||||
GIT_COMMITTER_EMAIL
|
||||
GIT_COMMITTER_DATE
|
||||
EMAIL
|
||||
|
||||
(nb "<", ">" and "\n"s are stripped)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ git-diff-files - Compares files in the working tree and the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|-n|--no-index] [<common diff options>] [<path>...]
|
||||
'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|--no-index] [<common diff options>] [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -36,7 +36,7 @@ omit diff output for unmerged entries and just show "Unmerged".
|
||||
diff, similar to the way 'diff-tree' shows a merge
|
||||
commit with these flags.
|
||||
|
||||
\-n,\--no-index::
|
||||
--no-index::
|
||||
Compare the two given files / directories.
|
||||
|
||||
-q::
|
||||
|
||||
@@ -8,7 +8,8 @@ git-fmt-merge-msg - Produce a merge commit message
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-fmt-merge-msg' <$GIT_DIR/FETCH_HEAD
|
||||
git-fmt-merge-msg [--summary | --no-summary] <$GIT_DIR/FETCH_HEAD
|
||||
git-fmt-merge-msg [--summary | --no-summray] -F <file>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -19,6 +20,28 @@ passed as the '<merge-message>' argument of `git-merge`.
|
||||
This script is intended mostly for internal use by scripts
|
||||
automatically invoking `git-merge`.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--summary::
|
||||
In addition to branch names, populate the log message with
|
||||
one-line descriptions from the actual commits that are being
|
||||
merged.
|
||||
|
||||
--no-summary::
|
||||
Do not list one-line descriptions from the actual commits being
|
||||
merged.
|
||||
|
||||
--file <file>, -F <file>::
|
||||
Take the list of merged objects from <file> instead of
|
||||
stdin.
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
|
||||
merge.summary::
|
||||
Whether to include summaries of merged commits in newly
|
||||
merge commit messages. False by default.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
@@ -12,12 +12,13 @@ SYNOPSIS
|
||||
'git-grep' [--cached]
|
||||
[-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
|
||||
[-v | --invert-match] [-h|-H] [--full-name]
|
||||
[-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings]
|
||||
[-n] [-l | --files-with-matches] [-L | --files-without-match]
|
||||
[-E | --extended-regexp] [-G | --basic-regexp]
|
||||
[-F | --fixed-strings] [-n]
|
||||
[-l | --files-with-matches] [-L | --files-without-match]
|
||||
[-c | --count] [--all-match]
|
||||
[-A <post-context>] [-B <pre-context>] [-C <context>]
|
||||
[-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...]
|
||||
[<tree>...]
|
||||
[-f <file>] [-e] <pattern>
|
||||
[--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
|
||||
[--] [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -39,6 +40,9 @@ OPTIONS
|
||||
Ignore case differences between the patterns and the
|
||||
files.
|
||||
|
||||
-I::
|
||||
Don't match the pattern in binary files.
|
||||
|
||||
-w | --word-regexp::
|
||||
Match the pattern only at word boundary (either begin at the
|
||||
beginning of a line, or preceded by a non-word character; end at
|
||||
@@ -64,6 +68,10 @@ OPTIONS
|
||||
Use POSIX extended/basic regexp for patterns. Default
|
||||
is to use basic regexp.
|
||||
|
||||
-F | --fixed-strings::
|
||||
Use fixed strings for patterns (don't interpret pattern
|
||||
as a regex).
|
||||
|
||||
-n::
|
||||
Prefix the line number to matching lines.
|
||||
|
||||
@@ -81,6 +89,9 @@ OPTIONS
|
||||
line containing `--` between contiguous groups of
|
||||
matches.
|
||||
|
||||
-<num>::
|
||||
A shortcut for specifying -C<num>.
|
||||
|
||||
-f <file>::
|
||||
Read patterns from <file>, one per line.
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ commit-id::
|
||||
|
||||
<commit-id>['\t'<filename-as-in--w>]
|
||||
|
||||
--recover::
|
||||
Verify that everything reachable from target is fetched. Used after
|
||||
an earlier fetch is interrupted.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
@@ -8,7 +8,7 @@ git-http-push - Push objects over HTTP/DAV to another repository
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-http-push' [--complete] [--force] [--verbose] <url> <ref> [<ref>...]
|
||||
'git-http-push' [--all] [--force] [--verbose] <url> <ref> [<ref>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -18,7 +18,7 @@ remote branch.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--complete::
|
||||
--all::
|
||||
Do not assume that the remote repository is complete in its
|
||||
current state, and verify all objects in the entire local
|
||||
ref's history exist in the remote repository.
|
||||
@@ -34,6 +34,15 @@ OPTIONS
|
||||
Report the list of objects being walked locally and the
|
||||
list of objects successfully sent to the remote repository.
|
||||
|
||||
-d, -D::
|
||||
Remove <ref> from remote repository. The specified branch
|
||||
cannot be the remote HEAD. If -d is specified the following
|
||||
other conditions must also be met:
|
||||
|
||||
- Remote HEAD must resolve to an object that exists locally
|
||||
- Specified branch resolves to an object that exists locally
|
||||
- Specified branch is an ancestor of the remote HEAD
|
||||
|
||||
<ref>...::
|
||||
The remote refs to update.
|
||||
|
||||
|
||||
@@ -24,6 +24,16 @@ OPTIONS
|
||||
Get all the objects.
|
||||
-v::
|
||||
Report what is downloaded.
|
||||
-s::
|
||||
Instead of regular file-to-file copying use symbolic links to the objects
|
||||
in the remote repository.
|
||||
-l::
|
||||
Before attempting symlinks (if -s is specified) or file-to-file copying the
|
||||
remote objects, try to hardlink the remote objects into the local
|
||||
repository.
|
||||
-n::
|
||||
Never attempt to file-to-file copy remote objects. Only useful with
|
||||
-s or -l command-line options.
|
||||
|
||||
-w <filename>::
|
||||
Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
|
||||
@@ -35,6 +45,10 @@ OPTIONS
|
||||
|
||||
<commit-id>['\t'<filename-as-in--w>]
|
||||
|
||||
--recover::
|
||||
Verify that everything reachable from target is fetched. Used after
|
||||
an earlier fetch is interrupted.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
|
||||
@@ -25,6 +25,7 @@ SYNOPSIS
|
||||
[ \--cherry-pick ]
|
||||
[ \--encoding[=<encoding>] ]
|
||||
[ \--(author|committer|grep)=<pattern> ]
|
||||
[ \--date={local|relative|default} ]
|
||||
[ [\--objects | \--objects-edge] [ \--unpacked ] ]
|
||||
[ \--pretty | \--header ]
|
||||
[ \--bisect ]
|
||||
@@ -90,9 +91,20 @@ include::pretty-formats.txt[]
|
||||
|
||||
--relative-date::
|
||||
|
||||
Show dates relative to the current time, e.g. "2 hours ago".
|
||||
Synonym for `--date=relative`.
|
||||
|
||||
--date={relative,local,default}::
|
||||
|
||||
Only takes effect for dates shown in human-readable format, such
|
||||
as when using "--pretty".
|
||||
+
|
||||
`--date=relative` shows dates relative to the current time,
|
||||
e.g. "2 hours ago".
|
||||
+
|
||||
`--date=local` shows timestamps in user's local timezone.
|
||||
+
|
||||
`--date=default` shows timestamps in the original timezone
|
||||
(either committer's or author's).
|
||||
|
||||
--header::
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
|
||||
--in-reply-to::
|
||||
Specify the contents of the first In-Reply-To header.
|
||||
Subsequent emails will refer to the previous email
|
||||
Subsequent emails will refer to the previous email
|
||||
instead of this if --chain-reply-to is set (the default)
|
||||
Only necessary if --compose is also set. If --compose
|
||||
is not set, this will be prompted for.
|
||||
@@ -68,8 +68,9 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
all that is output.
|
||||
|
||||
--smtp-server::
|
||||
If set, specifies the outgoing SMTP server to use. A full
|
||||
pathname of a sendmail-like program can be specified instead;
|
||||
If set, specifies the outgoing SMTP server to use (e.g.
|
||||
`smtp.example.com` or a raw IP address). Alternatively it can
|
||||
specify a full pathname of a sendmail-like program instead;
|
||||
the program must support the `-i` option. Default value can
|
||||
be specified by the 'sendemail.smtpserver' configuration
|
||||
option; the built-in default is `/usr/sbin/sendmail` or
|
||||
@@ -85,6 +86,15 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
Do not add the From: address to the cc: list, if it shows up in a From:
|
||||
line.
|
||||
|
||||
--dry-run::
|
||||
Do everything except actually send the emails.
|
||||
|
||||
--envelope-sender::
|
||||
Specify the envelope sender used to send the emails.
|
||||
This is useful if your default address is not the address that is
|
||||
subscribed to a list. If you use the sendmail binary, you must have
|
||||
suitable privileges for the -f parameter.
|
||||
|
||||
--to::
|
||||
Specify the primary recipient of the emails generated.
|
||||
Generally, this will be the upstream maintainer of the
|
||||
|
||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s]
|
||||
git-shortlog [-n|--number] [-s|--summary] [<committish>...]
|
||||
git-shortlog [-n|--numbered] [-s|--summary] [<committish>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -22,14 +22,14 @@ Additionally, "[PATCH]" will be stripped from the commit description.
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
-h::
|
||||
-h, \--help::
|
||||
Print a short usage message and exit.
|
||||
|
||||
-n::
|
||||
-n, \--numbered::
|
||||
Sort output according to the number of commits per author instead
|
||||
of author alphabetic order.
|
||||
|
||||
-s::
|
||||
-s, \--summary::
|
||||
Suppress commit description and provide a commit count summary only.
|
||||
|
||||
FILES
|
||||
|
||||
@@ -159,6 +159,12 @@ New features:
|
||||
Any other arguments are passed directly to `git log'
|
||||
|
||||
--
|
||||
'find-rev'::
|
||||
When given an SVN revision number of the form 'rN', returns the
|
||||
corresponding git commit hash (this can optionally be followed by a
|
||||
tree-ish to specify which branch should be searched). When given a
|
||||
tree-ish, returns the corresponding SVN revision number.
|
||||
|
||||
'set-tree'::
|
||||
You should consider using 'dcommit' instead of this command.
|
||||
Commit specified commit or tree objects to SVN. This relies on
|
||||
|
||||
@@ -29,6 +29,10 @@ in a coherent way to git enlightenment ;-).
|
||||
The COMMAND is either a name of a Git command (see below) or an alias
|
||||
as defined in the configuration file (see gitlink:git-config[1]).
|
||||
|
||||
Formatted and hyperlinked version of the latest git
|
||||
documentation can be viewed at
|
||||
`http://www.kernel.org/pub/software/scm/git/docs/`.
|
||||
|
||||
ifdef::stalenotes[]
|
||||
[NOTE]
|
||||
============
|
||||
@@ -344,6 +348,8 @@ git Commits
|
||||
'GIT_AUTHOR_DATE'::
|
||||
'GIT_COMMITTER_NAME'::
|
||||
'GIT_COMMITTER_EMAIL'::
|
||||
'GIT_COMMITTER_DATE'::
|
||||
'EMAIL'::
|
||||
see gitlink:git-commit-tree[1]
|
||||
|
||||
git Diffs
|
||||
|
||||
@@ -49,10 +49,12 @@ Set to a value::
|
||||
Unspecified::
|
||||
|
||||
No glob pattern matches the path, and nothing says if
|
||||
the path has or does not have the attribute.
|
||||
the path has or does not have the attribute, the
|
||||
attribute for the path is said to be Unspecified.
|
||||
|
||||
When more than one glob pattern matches the path, a later line
|
||||
overrides an earlier line.
|
||||
overrides an earlier line. This overriding is done per
|
||||
attribute.
|
||||
|
||||
When deciding what attributes are assigned to a path, git
|
||||
consults `$GIT_DIR/info/attributes` file (which has the highest
|
||||
@@ -76,12 +78,17 @@ are attributes-aware.
|
||||
Checking-out and checking-in
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The attribute `crlf` affects how the contents stored in the
|
||||
These attributes affect how the contents stored in the
|
||||
repository are copied to the working tree files when commands
|
||||
such as `git checkout` and `git merge` run. It also affects how
|
||||
such as `git checkout` and `git merge` run. They also affect how
|
||||
git stores the contents you prepare in the working tree in the
|
||||
repository upon `git add` and `git commit`.
|
||||
|
||||
`crlf`
|
||||
^^^^^^
|
||||
|
||||
This attribute controls the line-ending convention.
|
||||
|
||||
Set::
|
||||
|
||||
Setting the `crlf` attribute on a path is meant to mark
|
||||
@@ -127,6 +134,67 @@ converted to LF upon checkin, but there is no conversion done
|
||||
upon checkout.
|
||||
|
||||
|
||||
`ident`
|
||||
^^^^^^^
|
||||
|
||||
When the attribute `ident` is set to a path, git replaces
|
||||
`$ident$` in the blob object with `$ident:`, followed by
|
||||
40-character hexadecimal blob object name, followed by a dollar
|
||||
sign `$` upon checkout. Any byte sequence that begins with
|
||||
`$ident:` and ends with `$` in the worktree file is replaced
|
||||
with `$ident$` upon check-in.
|
||||
|
||||
|
||||
Interaction between checkin/checkout attributes
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the check-in codepath, the worktree file is first converted
|
||||
with `ident` (if specified), and then with `crlf` (again, if
|
||||
specified and applicable).
|
||||
|
||||
In the check-out codepath, the blob content is first converted
|
||||
with `crlf`, and then `ident`.
|
||||
|
||||
|
||||
`filter`
|
||||
^^^^^^^^
|
||||
|
||||
A `filter` attribute can be set to a string value. This names
|
||||
filter driver specified in the configuration.
|
||||
|
||||
A filter driver consists of `clean` command and `smudge`
|
||||
command, either of which can be left unspecified. Upon
|
||||
checkout, when `smudge` command is specified, the command is fed
|
||||
the blob object from its standard input, and its standard output
|
||||
is used to update the worktree file. Similarly, `clean` command
|
||||
is used to convert the contents of worktree file upon checkin.
|
||||
|
||||
Missing filter driver definition in the config is not an error
|
||||
but makes the filter a no-op passthru.
|
||||
|
||||
The content filtering is done to massage the content into a
|
||||
shape that is more convenient for the platform, filesystem, and
|
||||
the user to use. The keyword here is "more convenient" and not
|
||||
"turning something unusable into usable". In other words, it is
|
||||
"hanging yourself because we gave you a long rope" if your
|
||||
project uses filtering mechanism in such a way that it makes
|
||||
your project unusable unless the checkout is done with a
|
||||
specific filter in effect.
|
||||
|
||||
|
||||
Interaction between checkin/checkout attributes
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the check-in codepath, the worktree file is first converted
|
||||
with `filter` driver (if specified and corresponding driver
|
||||
defined), then the result is processed with `ident` (if
|
||||
specified), and then finally with `crlf` (again, if specified
|
||||
and applicable).
|
||||
|
||||
In the check-out codepath, the blob content is first converted
|
||||
with `crlf`, and then `ident` and fed to `filter`.
|
||||
|
||||
|
||||
Generating diff text
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -215,7 +283,7 @@ String::
|
||||
merge driver. The built-in 3-way merge driver can be
|
||||
explicitly specified by asking for "text" driver; the
|
||||
built-in "take the current branch" driver can be
|
||||
requested by "binary".
|
||||
requested with "binary".
|
||||
|
||||
|
||||
Defining a custom merge driver
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.1.2.GIT
|
||||
DEF_VER=v1.5.2-rc1.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
19
Makefile
19
Makefile
@@ -141,7 +141,12 @@ prefix = $(HOME)
|
||||
bindir = $(prefix)/bin
|
||||
gitexecdir = $(bindir)
|
||||
template_dir = $(prefix)/share/git-core/templates/
|
||||
ETC_GITCONFIG = $(prefix)/etc/gitconfig
|
||||
ifeq ($(prefix),/usr)
|
||||
sysconfdir = /etc
|
||||
else
|
||||
sysconfdir = $(prefix)/etc
|
||||
endif
|
||||
ETC_GITCONFIG = $(sysconfdir)/gitconfig
|
||||
# DESTDIR=
|
||||
|
||||
# default configuration for gitweb
|
||||
@@ -160,7 +165,7 @@ GITWEB_FAVICON = git-favicon.png
|
||||
GITWEB_SITE_HEADER =
|
||||
GITWEB_SITE_FOOTER =
|
||||
|
||||
export prefix bindir gitexecdir template_dir
|
||||
export prefix bindir gitexecdir template_dir sysconfdir
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
@@ -283,7 +288,7 @@ LIB_H = \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
|
||||
spawn-pipe.h \
|
||||
utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h
|
||||
utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
@@ -306,7 +311,7 @@ LIB_OBJS = \
|
||||
write_or_die.o trace.o list-objects.o grep.o match-trees.o \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
|
||||
convert.o attr.o decorate.o progress.o
|
||||
convert.o attr.o decorate.o progress.o mailmap.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
@@ -953,6 +958,10 @@ endif
|
||||
|
||||
### Testing rules
|
||||
|
||||
TEST_PROGRAMS = test-chmtime$X test-genrandom$X
|
||||
|
||||
all: $(TEST_PROGRAMS)
|
||||
|
||||
# GNU make supports exporting all variables by "export" without parameters.
|
||||
# However, the environment gets quite big, and some programs have problems
|
||||
# with that.
|
||||
@@ -960,7 +969,7 @@ endif
|
||||
export NO_SYMLINKS
|
||||
export NO_SVN_TESTS
|
||||
|
||||
test: all test-chmtime$X test-genrandom$X
|
||||
test: all
|
||||
$(MAKE) -C t/ all
|
||||
|
||||
test-date$X: test-date.c date.o ctype.o
|
||||
|
||||
@@ -16,16 +16,20 @@
|
||||
#include "quote.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "cache-tree.h"
|
||||
#include "path-list.h"
|
||||
#include "mailmap.h"
|
||||
|
||||
static char blame_usage[] =
|
||||
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
|
||||
"git-blame [-c] [-b] [-l] [--root] [-x] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
|
||||
" -c Use the same output mode as git-annotate (Default: off)\n"
|
||||
" -b Show blank SHA-1 for boundary commits (Default: off)\n"
|
||||
" -l Show long commit SHA1 (Default: off)\n"
|
||||
" --root Do not treat root commits as boundaries (Default: off)\n"
|
||||
" -t Show raw timestamp (Default: off)\n"
|
||||
" -x Do not use .mailmap file\n"
|
||||
" -f, --show-name Show original filename (Default: auto)\n"
|
||||
" -n, --show-number Show original linenumber (Default: off)\n"
|
||||
" -s Suppress author name and timestamp (Default: off)\n"
|
||||
" -p, --porcelain Show in a format designed for machine consumption\n"
|
||||
" -L n,m Process only line range n,m, counting from 1\n"
|
||||
" -M, -C Find line movements within and across files\n"
|
||||
@@ -42,6 +46,8 @@ static int show_root;
|
||||
static int blank_boundary;
|
||||
static int incremental;
|
||||
static int cmd_is_annotate;
|
||||
static int no_mailmap;
|
||||
static struct path_list mailmap;
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
@@ -1264,8 +1270,8 @@ static void get_ac_line(const char *inbuf, const char *what,
|
||||
int bufsz, char *person, const char **mail,
|
||||
unsigned long *time, const char **tz)
|
||||
{
|
||||
int len;
|
||||
char *tmp, *endp;
|
||||
int len, tzlen, maillen;
|
||||
char *tmp, *endp, *timepos;
|
||||
|
||||
tmp = strstr(inbuf, what);
|
||||
if (!tmp)
|
||||
@@ -1291,17 +1297,42 @@ static void get_ac_line(const char *inbuf, const char *what,
|
||||
while (*tmp != ' ')
|
||||
tmp--;
|
||||
*tz = tmp+1;
|
||||
tzlen = (person+len)-(tmp+1);
|
||||
|
||||
*tmp = 0;
|
||||
while (*tmp != ' ')
|
||||
tmp--;
|
||||
*time = strtoul(tmp, NULL, 10);
|
||||
timepos = tmp;
|
||||
|
||||
*tmp = 0;
|
||||
while (*tmp != ' ')
|
||||
tmp--;
|
||||
*mail = tmp + 1;
|
||||
*tmp = 0;
|
||||
maillen = timepos - tmp;
|
||||
|
||||
if (!mailmap.nr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* mailmap expansion may make the name longer.
|
||||
* make room by pushing stuff down.
|
||||
*/
|
||||
tmp = person + bufsz - (tzlen + 1);
|
||||
memmove(tmp, *tz, tzlen);
|
||||
tmp[tzlen] = 0;
|
||||
*tz = tmp;
|
||||
|
||||
tmp = tmp - (maillen + 1);
|
||||
memmove(tmp, *mail, maillen);
|
||||
tmp[maillen] = 0;
|
||||
*mail = tmp;
|
||||
|
||||
/*
|
||||
* Now, convert e-mail using mailmap
|
||||
*/
|
||||
map_email(&mailmap, tmp + 1, person, tmp-person-1);
|
||||
}
|
||||
|
||||
static void get_commit_info(struct commit *commit,
|
||||
@@ -1483,6 +1514,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
|
||||
#define OUTPUT_SHOW_NAME 020
|
||||
#define OUTPUT_SHOW_NUMBER 040
|
||||
#define OUTPUT_SHOW_SCORE 0100
|
||||
#define OUTPUT_NO_AUTHOR 0200
|
||||
|
||||
static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
|
||||
{
|
||||
@@ -1577,10 +1609,15 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
|
||||
if (opt & OUTPUT_SHOW_NUMBER)
|
||||
printf(" %*d", max_orig_digits,
|
||||
ent->s_lno + 1 + cnt);
|
||||
printf(" (%-*.*s %10s %*d) ",
|
||||
longest_author, longest_author, ci.author,
|
||||
format_time(ci.author_time, ci.author_tz,
|
||||
show_raw_time),
|
||||
|
||||
if (!(opt & OUTPUT_NO_AUTHOR))
|
||||
printf(" (%-*.*s %10s",
|
||||
longest_author, longest_author,
|
||||
ci.author,
|
||||
format_time(ci.author_time,
|
||||
ci.author_tz,
|
||||
show_raw_time));
|
||||
printf(" %*d) ",
|
||||
max_digits, ent->lno + 1 + cnt);
|
||||
}
|
||||
do {
|
||||
@@ -2092,6 +2129,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
output_option |= OUTPUT_RAW_TIMESTAMP;
|
||||
else if (!strcmp("-l", arg))
|
||||
output_option |= OUTPUT_LONG_OBJECT_NAME;
|
||||
else if (!strcmp("-s", arg))
|
||||
output_option |= OUTPUT_NO_AUTHOR;
|
||||
else if (!strcmp("-S", arg) && ++i < argc)
|
||||
revs_file = argv[i];
|
||||
else if (!prefixcmp(arg, "-M")) {
|
||||
@@ -2134,6 +2173,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
else if (!strcmp("-p", arg) ||
|
||||
!strcmp("--porcelain", arg))
|
||||
output_option |= OUTPUT_PORCELAIN;
|
||||
else if (!strcmp("-x", arg) ||
|
||||
!strcmp("--no-mailmap", arg))
|
||||
no_mailmap = 1;
|
||||
else if (!strcmp("--", arg)) {
|
||||
seen_dashdash = 1;
|
||||
i++;
|
||||
@@ -2333,6 +2375,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
die("reading graft file %s failed: %s",
|
||||
revs_file, strerror(errno));
|
||||
|
||||
if (!no_mailmap)
|
||||
read_mailmap(&mailmap, ".mailmap", NULL);
|
||||
|
||||
assign_blame(&sb, &revs, opt);
|
||||
|
||||
if (incremental)
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
*/
|
||||
static void init_buffer(char **bufp, unsigned int *sizep)
|
||||
{
|
||||
char *buf = xmalloc(BLOCKING);
|
||||
*bufp = xmalloc(BLOCKING);
|
||||
*sizep = 0;
|
||||
*bufp = buf;
|
||||
}
|
||||
|
||||
static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "builtin.h"
|
||||
|
||||
static const char diff_files_usage[] =
|
||||
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|-n|--no-index] [<common diff options>] [<path>...]"
|
||||
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|--no-index] [<common diff options>] [<path>...]"
|
||||
COMMON_DIFF_OPTIONS_HELP;
|
||||
|
||||
int cmd_diff_files(int argc, const char **argv, const char *prefix)
|
||||
|
||||
@@ -13,13 +13,10 @@
|
||||
#include "log-tree.h"
|
||||
#include "builtin.h"
|
||||
|
||||
/* NEEDSWORK: struct object has place for name but we _do_
|
||||
* know mode when we extracted the blob out of a tree, which
|
||||
* we currently lose.
|
||||
*/
|
||||
struct blobinfo {
|
||||
unsigned char sha1[20];
|
||||
const char *name;
|
||||
unsigned mode;
|
||||
};
|
||||
|
||||
static const char builtin_diff_usage[] =
|
||||
@@ -35,7 +32,7 @@ static void stuff_change(struct diff_options *opt,
|
||||
struct diff_filespec *one, *two;
|
||||
|
||||
if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) &&
|
||||
!hashcmp(old_sha1, new_sha1))
|
||||
!hashcmp(old_sha1, new_sha1) && (old_mode == new_mode))
|
||||
return;
|
||||
|
||||
if (opt->reverse_diff) {
|
||||
@@ -70,8 +67,12 @@ static int builtin_diff_b_f(struct rev_info *revs,
|
||||
die("'%s': %s", path, strerror(errno));
|
||||
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
|
||||
die("'%s': not a regular file or symlink", path);
|
||||
|
||||
if (blob[0].mode == S_IFINVALID)
|
||||
blob[0].mode = canon_mode(st.st_mode);
|
||||
|
||||
stuff_change(&revs->diffopt,
|
||||
canon_mode(st.st_mode), canon_mode(st.st_mode),
|
||||
blob[0].mode, canon_mode(st.st_mode),
|
||||
blob[0].sha1, null_sha1,
|
||||
path, path);
|
||||
diffcore_std(&revs->diffopt);
|
||||
@@ -88,8 +89,14 @@ static int builtin_diff_blobs(struct rev_info *revs,
|
||||
if (argc > 1)
|
||||
usage(builtin_diff_usage);
|
||||
|
||||
if (blob[0].mode == S_IFINVALID)
|
||||
blob[0].mode = mode;
|
||||
|
||||
if (blob[1].mode == S_IFINVALID)
|
||||
blob[1].mode = mode;
|
||||
|
||||
stuff_change(&revs->diffopt,
|
||||
mode, mode,
|
||||
blob[0].mode, blob[1].mode,
|
||||
blob[0].sha1, blob[1].sha1,
|
||||
blob[0].name, blob[1].name);
|
||||
diffcore_std(&revs->diffopt);
|
||||
@@ -272,6 +279,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
die("more than two blobs given: '%s'", name);
|
||||
hashcpy(blob[blobs].sha1, obj->sha1);
|
||||
blob[blobs].name = name;
|
||||
blob[blobs].mode = list->mode;
|
||||
blobs++;
|
||||
continue;
|
||||
|
||||
|
||||
@@ -35,16 +35,13 @@ static int update_ref(const char *action,
|
||||
unsigned char *sha1,
|
||||
unsigned char *oldval)
|
||||
{
|
||||
int len;
|
||||
char msg[1024];
|
||||
char *rla = getenv("GIT_REFLOG_ACTION");
|
||||
static struct ref_lock *lock;
|
||||
|
||||
if (!rla)
|
||||
rla = "(reflog update)";
|
||||
len = snprintf(msg, sizeof(msg), "%s: %s", rla, action);
|
||||
if (sizeof(msg) <= len)
|
||||
die("insanely long action");
|
||||
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
|
||||
lock = lock_any_ref_for_update(refname, oldval);
|
||||
if (!lock)
|
||||
return 1;
|
||||
|
||||
@@ -219,6 +219,7 @@ static int fsck_tree(struct tree *item)
|
||||
{
|
||||
int retval;
|
||||
int has_full_path = 0;
|
||||
int has_empty_name = 0;
|
||||
int has_zero_pad = 0;
|
||||
int has_bad_modes = 0;
|
||||
int has_dup_entries = 0;
|
||||
@@ -242,6 +243,8 @@ static int fsck_tree(struct tree *item)
|
||||
|
||||
if (strchr(name, '/'))
|
||||
has_full_path = 1;
|
||||
if (!*name)
|
||||
has_empty_name = 1;
|
||||
has_zero_pad |= *(char *)desc.buffer == '0';
|
||||
update_tree_entry(&desc);
|
||||
|
||||
@@ -291,6 +294,9 @@ static int fsck_tree(struct tree *item)
|
||||
if (has_full_path) {
|
||||
objwarning(&item->object, "contains full pathnames");
|
||||
}
|
||||
if (has_empty_name) {
|
||||
objwarning(&item->object, "contains empty pathname");
|
||||
}
|
||||
if (has_zero_pad) {
|
||||
objwarning(&item->object, "contains zero-padded file modes");
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ static void show_commit(struct commit *commit)
|
||||
static char pretty_header[16384];
|
||||
pretty_print_commit(revs.commit_format, commit, ~0,
|
||||
pretty_header, sizeof(pretty_header),
|
||||
revs.abbrev, NULL, NULL, revs.relative_date);
|
||||
revs.abbrev, NULL, NULL, revs.date_mode);
|
||||
printf("%s%c", pretty_header, hdr_termination);
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "path-list.h"
|
||||
#include "revision.h"
|
||||
#include "utf8.h"
|
||||
#include "mailmap.h"
|
||||
|
||||
static const char shortlog_usage[] =
|
||||
"git-shortlog [-n] [-s] [<commit-id>... ]";
|
||||
@@ -26,83 +27,6 @@ static int compare_by_number(const void *a1, const void *a2)
|
||||
|
||||
static struct path_list mailmap = {NULL, 0, 0, 0};
|
||||
|
||||
static int read_mailmap(const char *filename)
|
||||
{
|
||||
char buffer[1024];
|
||||
FILE *f = fopen(filename, "r");
|
||||
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
while (fgets(buffer, sizeof(buffer), f) != NULL) {
|
||||
char *end_of_name, *left_bracket, *right_bracket;
|
||||
char *name, *email;
|
||||
int i;
|
||||
if (buffer[0] == '#') {
|
||||
static const char abbrev[] = "# repo-abbrev:";
|
||||
int abblen = sizeof(abbrev) - 1;
|
||||
int len = strlen(buffer);
|
||||
|
||||
if (len && buffer[len - 1] == '\n')
|
||||
buffer[--len] = 0;
|
||||
if (!strncmp(buffer, abbrev, abblen)) {
|
||||
char *cp;
|
||||
|
||||
if (common_repo_prefix)
|
||||
free(common_repo_prefix);
|
||||
common_repo_prefix = xmalloc(len);
|
||||
|
||||
for (cp = buffer + abblen; isspace(*cp); cp++)
|
||||
; /* nothing */
|
||||
strcpy(common_repo_prefix, cp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((left_bracket = strchr(buffer, '<')) == NULL)
|
||||
continue;
|
||||
if ((right_bracket = strchr(left_bracket + 1, '>')) == NULL)
|
||||
continue;
|
||||
if (right_bracket == left_bracket + 1)
|
||||
continue;
|
||||
for (end_of_name = left_bracket; end_of_name != buffer
|
||||
&& isspace(end_of_name[-1]); end_of_name--)
|
||||
/* keep on looking */
|
||||
if (end_of_name == buffer)
|
||||
continue;
|
||||
name = xmalloc(end_of_name - buffer + 1);
|
||||
strlcpy(name, buffer, end_of_name - buffer + 1);
|
||||
email = xmalloc(right_bracket - left_bracket);
|
||||
for (i = 0; i < right_bracket - left_bracket - 1; i++)
|
||||
email[i] = tolower(left_bracket[i + 1]);
|
||||
email[right_bracket - left_bracket - 1] = '\0';
|
||||
path_list_insert(email, &mailmap)->util = name;
|
||||
}
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_email(char *email, char *name, int maxlen)
|
||||
{
|
||||
char *p;
|
||||
struct path_list_item *item;
|
||||
|
||||
/* autocomplete common developers */
|
||||
p = strchr(email, '>');
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
*p = '\0';
|
||||
/* downcase the email address */
|
||||
for (p = email; *p; p++)
|
||||
*p = tolower(*p);
|
||||
item = path_list_lookup(email, &mailmap);
|
||||
if (item != NULL) {
|
||||
const char *realname = (const char *)item->util;
|
||||
strncpy(name, realname, maxlen);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void insert_author_oneline(struct path_list *list,
|
||||
const char *author, int authorlen,
|
||||
const char *oneline, int onelinelen)
|
||||
@@ -184,7 +108,7 @@ static void read_from_stdin(struct path_list *list)
|
||||
(bob = strchr(buffer + 7, '<')) != NULL) {
|
||||
char buffer2[1024], offset = 0;
|
||||
|
||||
if (map_email(bob + 1, buffer, sizeof(buffer)))
|
||||
if (map_email(&mailmap, bob + 1, buffer, sizeof(buffer)))
|
||||
bob = buffer + strlen(buffer);
|
||||
else {
|
||||
offset = 8;
|
||||
@@ -238,7 +162,7 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
||||
die("Invalid commit buffer: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (map_email(bracket + 1, scratch,
|
||||
if (map_email(&mailmap, bracket + 1, scratch,
|
||||
sizeof(scratch))) {
|
||||
author = scratch;
|
||||
authorlen = strlen(scratch);
|
||||
@@ -359,8 +283,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
if (argc > 1)
|
||||
die ("unrecognized argument: %s", argv[1]);
|
||||
|
||||
if (!access(".mailmap", R_OK))
|
||||
read_mailmap(".mailmap");
|
||||
read_mailmap(&mailmap, ".mailmap", &common_repo_prefix);
|
||||
|
||||
if (rev.pending.nr == 0) {
|
||||
if (isatty(0))
|
||||
|
||||
@@ -36,8 +36,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
|
||||
die("git-write-tree: error building trees");
|
||||
if (0 <= newfd) {
|
||||
if (!write_cache(newfd, active_cache, active_nr)
|
||||
&& !close(newfd))
|
||||
&& !close(newfd)) {
|
||||
commit_lock_file(lock_file);
|
||||
newfd = -1;
|
||||
}
|
||||
}
|
||||
/* Not being able to write is fine -- we are only interested
|
||||
* in updating the cache-tree part, and if the next caller
|
||||
@@ -55,6 +57,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
|
||||
else
|
||||
hashcpy(sha1, active_cache_tree->sha1);
|
||||
|
||||
if (0 <= newfd)
|
||||
close(newfd);
|
||||
rollback_lock_file(lock_file);
|
||||
|
||||
return 0;
|
||||
|
||||
66
cache.h
66
cache.h
@@ -24,6 +24,9 @@
|
||||
#define DTYPE(de) DT_UNKNOWN
|
||||
#endif
|
||||
|
||||
/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */
|
||||
#define S_IFINVALID 0030000
|
||||
|
||||
/*
|
||||
* A "directory link" is a link to another git directory.
|
||||
*
|
||||
@@ -143,9 +146,37 @@ static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned in
|
||||
|
||||
#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
|
||||
|
||||
extern struct cache_entry **active_cache;
|
||||
extern unsigned int active_nr, active_alloc, active_cache_changed;
|
||||
extern struct cache_tree *active_cache_tree;
|
||||
struct index_state {
|
||||
struct cache_entry **cache;
|
||||
unsigned int cache_nr, cache_alloc, cache_changed;
|
||||
struct cache_tree *cache_tree;
|
||||
time_t timestamp;
|
||||
void *mmap;
|
||||
size_t mmap_size;
|
||||
};
|
||||
|
||||
extern struct index_state the_index;
|
||||
|
||||
#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
|
||||
#define active_cache (the_index.cache)
|
||||
#define active_nr (the_index.cache_nr)
|
||||
#define active_alloc (the_index.cache_alloc)
|
||||
#define active_cache_changed (the_index.cache_changed)
|
||||
#define active_cache_tree (the_index.cache_tree)
|
||||
|
||||
#define read_cache() read_index(&the_index)
|
||||
#define read_cache_from(path) read_index_from(&the_index, (path))
|
||||
#define write_cache(newfd, cache, entries) write_index(&the_index, (newfd))
|
||||
#define discard_cache() discard_index(&the_index)
|
||||
#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
|
||||
#define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))
|
||||
#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
|
||||
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
|
||||
#define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
|
||||
#define refresh_cache(flags) refresh_index(&the_index, flags)
|
||||
#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really))
|
||||
#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really))
|
||||
#endif
|
||||
|
||||
enum object_type {
|
||||
OBJ_BAD = -1,
|
||||
@@ -195,23 +226,23 @@ extern void verify_non_filename(const char *prefix, const char *name);
|
||||
#define alloc_nr(x) (((x)+16)*3/2)
|
||||
|
||||
/* Initialize and use the cache information */
|
||||
extern int read_cache(void);
|
||||
extern int read_cache_from(const char *path);
|
||||
extern int write_cache(int newfd, struct cache_entry **cache, int entries);
|
||||
extern int discard_cache(void);
|
||||
extern int read_index(struct index_state *);
|
||||
extern int read_index_from(struct index_state *, const char *path);
|
||||
extern int write_index(struct index_state *, int newfd);
|
||||
extern int discard_index(struct index_state *);
|
||||
extern int verify_path(const char *path);
|
||||
extern int cache_name_pos(const char *name, int namelen);
|
||||
extern int index_name_pos(struct index_state *, const char *name, int namelen);
|
||||
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
|
||||
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
|
||||
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
|
||||
extern int add_cache_entry(struct cache_entry *ce, int option);
|
||||
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
|
||||
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
|
||||
extern int remove_cache_entry_at(int pos);
|
||||
extern int remove_file_from_cache(const char *path);
|
||||
extern int add_file_to_cache(const char *path, int verbose);
|
||||
extern int remove_index_entry_at(struct index_state *, int pos);
|
||||
extern int remove_file_from_index(struct index_state *, const char *path);
|
||||
extern int add_file_to_index(struct index_state *, const char *path, int verbose);
|
||||
extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
|
||||
extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int);
|
||||
extern int ce_modified(struct cache_entry *ce, struct stat *st, int);
|
||||
extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int);
|
||||
extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
|
||||
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
||||
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
|
||||
extern int read_pipe(int fd, char** return_buf, unsigned long* return_size);
|
||||
@@ -223,7 +254,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
||||
#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
|
||||
#define REFRESH_QUIET 0x0004 /* be quiet about it */
|
||||
#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
|
||||
extern int refresh_cache(unsigned int flags);
|
||||
extern int refresh_index(struct index_state *, unsigned int flags);
|
||||
|
||||
struct lock_file {
|
||||
struct lock_file *next;
|
||||
@@ -340,6 +371,7 @@ static inline unsigned int hexval(unsigned int c)
|
||||
#define DEFAULT_ABBREV 7
|
||||
|
||||
extern int get_sha1(const char *str, unsigned char *sha1);
|
||||
extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
|
||||
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||
@@ -358,7 +390,7 @@ extern void *read_object_with_reference(const unsigned char *sha1,
|
||||
unsigned long *size,
|
||||
unsigned char *sha1_ret);
|
||||
|
||||
enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT };
|
||||
enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT, DATE_LOCAL };
|
||||
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
|
||||
const char *show_rfc2822_date(unsigned long time, int timezone);
|
||||
int parse_date(const char *date, char *buf, int bufsize);
|
||||
@@ -378,7 +410,7 @@ struct checkout {
|
||||
refresh_cache:1;
|
||||
};
|
||||
|
||||
extern int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath);
|
||||
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
|
||||
|
||||
extern struct alternate_object_database {
|
||||
struct alternate_object_database *next;
|
||||
|
||||
12
commit.c
12
commit.c
@@ -526,7 +526,7 @@ static int add_rfc2047(char *buf, const char *line, int len,
|
||||
}
|
||||
|
||||
static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
|
||||
const char *line, int relative_date,
|
||||
const char *line, enum date_mode dmode,
|
||||
const char *encoding)
|
||||
{
|
||||
char *date;
|
||||
@@ -569,7 +569,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
|
||||
switch (fmt) {
|
||||
case CMIT_FMT_MEDIUM:
|
||||
ret += sprintf(buf + ret, "Date: %s\n",
|
||||
show_date(time, tz, relative_date));
|
||||
show_date(time, tz, dmode));
|
||||
break;
|
||||
case CMIT_FMT_EMAIL:
|
||||
ret += sprintf(buf + ret, "Date: %s\n",
|
||||
@@ -577,7 +577,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
|
||||
break;
|
||||
case CMIT_FMT_FULLER:
|
||||
ret += sprintf(buf + ret, "%sDate: %s\n", what,
|
||||
show_date(time, tz, relative_date));
|
||||
show_date(time, tz, dmode));
|
||||
break;
|
||||
default:
|
||||
/* notin' */
|
||||
@@ -919,7 +919,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
||||
char *buf, unsigned long space,
|
||||
int abbrev, const char *subject,
|
||||
const char *after_subject,
|
||||
int relative_date)
|
||||
enum date_mode dmode)
|
||||
{
|
||||
int hdr = 1, body = 0, seen_title = 0;
|
||||
unsigned long offset = 0;
|
||||
@@ -1023,14 +1023,14 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
||||
offset += add_user_info("Author", fmt,
|
||||
buf + offset,
|
||||
line + 7,
|
||||
relative_date,
|
||||
dmode,
|
||||
encoding);
|
||||
if (!memcmp(line, "committer ", 10) &&
|
||||
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))
|
||||
offset += add_user_info("Commit", fmt,
|
||||
buf + offset,
|
||||
line + 10,
|
||||
relative_date,
|
||||
dmode,
|
||||
encoding);
|
||||
continue;
|
||||
}
|
||||
|
||||
2
commit.h
2
commit.h
@@ -61,7 +61,7 @@ enum cmit_fmt {
|
||||
};
|
||||
|
||||
extern enum cmit_fmt get_commit_format(const char *arg);
|
||||
extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, int relative_date);
|
||||
extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);
|
||||
|
||||
/** Removes the first commit from a list sorted by date, and adds all
|
||||
* of its parents.
|
||||
|
||||
@@ -52,6 +52,7 @@ foreach my $tar_file (@ARGV)
|
||||
Z8 Z1 Z100 Z6
|
||||
Z2 Z32 Z32 Z8 Z8 Z*', $_;
|
||||
last unless $name;
|
||||
next if $name =~ m{/\z};
|
||||
$mode = oct $mode;
|
||||
$size = oct $size;
|
||||
$mtime = oct $mtime;
|
||||
@@ -64,7 +65,12 @@ foreach my $tar_file (@ARGV)
|
||||
}
|
||||
print FI "\n";
|
||||
|
||||
my $path = "$prefix$name";
|
||||
my $path;
|
||||
if ($prefix) {
|
||||
$path = "$prefix/$name";
|
||||
} else {
|
||||
$path = "$name";
|
||||
}
|
||||
$files{$path} = [$next_mark++, $mode];
|
||||
|
||||
$commit_time = $mtime if $mtime > $commit_time;
|
||||
|
||||
@@ -302,7 +302,7 @@ generate_update_branch_email()
|
||||
# List all of the revisions that were removed by this update, in a fast forward
|
||||
# update, this list will be empty, because rev-list O ^N is empty. For a non
|
||||
# fast forward, O ^N is the list of removed revisions
|
||||
fastforward=""
|
||||
fast_forward=""
|
||||
rev=""
|
||||
for rev in $(git rev-list $newrev..$oldrev)
|
||||
do
|
||||
@@ -327,36 +327,67 @@ generate_update_branch_email()
|
||||
if [ -z "$fastforward" ]; then
|
||||
echo " from $oldrev ($oldrev_type)"
|
||||
else
|
||||
# 1. Existing revisions were removed. In this case newrev is a
|
||||
# subset of oldrev - this is the reverse of a fast-forward,
|
||||
# a rewind
|
||||
# 2. New revisions were added on top of an old revision, this is
|
||||
# a rewind and addition.
|
||||
|
||||
# (1) certainly happened, (2) possibly. When (2) hasn't happened,
|
||||
# we set a flag to indicate that no log printout is required.
|
||||
|
||||
echo ""
|
||||
echo "This update added new revisions after undoing old revisions. That is to"
|
||||
echo "say, the old revision is not a strict subset of the new revision. This"
|
||||
echo "situation occurs when you --force push a change and generate a"
|
||||
echo "repository containing something like this:"
|
||||
echo ""
|
||||
echo " * -- * -- B -- O -- O -- O ($oldrev)"
|
||||
echo " \\"
|
||||
echo " N -- N -- N ($newrev)"
|
||||
echo ""
|
||||
echo "When this happens we assume that you've already had alert emails for all"
|
||||
echo "of the O revisions, and so we here report only the revisions in the N"
|
||||
echo "branch from the common base, B."
|
||||
|
||||
# Find the common ancestor of the old and new revisions and compare
|
||||
# it with newrev
|
||||
baserev=$(git merge-base $oldrev $newrev)
|
||||
rewind_only=""
|
||||
if [ "$baserev" = "$newrev" ]; then
|
||||
echo "This update discarded existing revisions and left the branch pointing at"
|
||||
echo "a previous point in the repository history."
|
||||
echo ""
|
||||
echo " * -- * -- N ($newrev)"
|
||||
echo " \\"
|
||||
echo " O -- O -- O ($oldrev)"
|
||||
echo ""
|
||||
echo "The removed revisions are not necessarilly gone - if another reference"
|
||||
echo "still refers to them they will stay in the repository."
|
||||
rewind_only=1
|
||||
else
|
||||
echo "This update added new revisions after undoing existing revisions. That is"
|
||||
echo "to say, the old revision is not a strict subset of the new revision. This"
|
||||
echo "situation occurs when you --force push a change and generate a repository"
|
||||
echo "containing something like this:"
|
||||
echo ""
|
||||
echo " * -- * -- B -- O -- O -- O ($oldrev)"
|
||||
echo " \\"
|
||||
echo " N -- N -- N ($newrev)"
|
||||
echo ""
|
||||
echo "When this happens we assume that you've already had alert emails for all"
|
||||
echo "of the O revisions, and so we here report only the revisions in the N"
|
||||
echo "branch from the common base, B."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Those revisions listed above that are new to this repository have"
|
||||
echo "not appeared on any other notification email; so we list those"
|
||||
echo "revisions in full, below."
|
||||
if [ -z "$rewind_only" ]; then
|
||||
echo "Those revisions listed above that are new to this repository have"
|
||||
echo "not appeared on any other notification email; so we list those"
|
||||
echo "revisions in full, below."
|
||||
|
||||
echo ""
|
||||
echo $LOGBEGIN
|
||||
git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
|
||||
git rev-list --pretty --stdin $oldrev..$newrev
|
||||
echo ""
|
||||
echo $LOGBEGIN
|
||||
git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
|
||||
git rev-list --pretty --stdin $oldrev..$newrev
|
||||
|
||||
# XXX: Need a way of detecting whether git rev-list actually outputted
|
||||
# anything, so that we can issue a "no new revisions added by this
|
||||
# update" message
|
||||
# XXX: Need a way of detecting whether git rev-list actually outputted
|
||||
# anything, so that we can issue a "no new revisions added by this
|
||||
# update" message
|
||||
|
||||
echo $LOGEND
|
||||
echo $LOGEND
|
||||
else
|
||||
echo "No new revisions were added by this update."
|
||||
fi
|
||||
|
||||
# The diffstat is shown from the old revision to the new revision. This
|
||||
# is to show the truth of what happened in this change. There's no point
|
||||
@@ -556,7 +587,7 @@ if [ -z "$GIT_DIR" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
projectdesc=$(sed -e '1p' "$GIT_DIR/description")
|
||||
projectdesc=$(sed -ne '1p' "$GIT_DIR/description")
|
||||
# Check if the description is unchanged from it's default, and shorten it to a
|
||||
# more manageable length if it is
|
||||
if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null
|
||||
|
||||
425
convert.c
425
convert.c
@@ -1,5 +1,6 @@
|
||||
#include "cache.h"
|
||||
#include "attr.h"
|
||||
#include "run-command.h"
|
||||
|
||||
/*
|
||||
* convert.c - convert a file when checking it out and checking it in.
|
||||
@@ -200,13 +201,350 @@ static char *crlf_to_worktree(const char *path, const char *src, unsigned long *
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int filter_buffer(const char *path, const char *src,
|
||||
unsigned long size, const char *cmd)
|
||||
{
|
||||
/*
|
||||
* Spawn cmd and feed the buffer contents through its stdin.
|
||||
*/
|
||||
struct child_process child_process;
|
||||
int pipe_feed[2];
|
||||
int write_err, status;
|
||||
|
||||
memset(&child_process, 0, sizeof(child_process));
|
||||
|
||||
if (pipe(pipe_feed) < 0) {
|
||||
error("cannot create pipe to run external filter %s", cmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
child_process.pid = fork();
|
||||
if (child_process.pid < 0) {
|
||||
error("cannot fork to run external filter %s", cmd);
|
||||
close(pipe_feed[0]);
|
||||
close(pipe_feed[1]);
|
||||
return 1;
|
||||
}
|
||||
if (!child_process.pid) {
|
||||
dup2(pipe_feed[0], 0);
|
||||
close(pipe_feed[0]);
|
||||
close(pipe_feed[1]);
|
||||
execlp("sh", "sh", "-c", cmd, NULL);
|
||||
return 1;
|
||||
}
|
||||
close(pipe_feed[0]);
|
||||
|
||||
write_err = (write_in_full(pipe_feed[1], src, size) < 0);
|
||||
if (close(pipe_feed[1]))
|
||||
write_err = 1;
|
||||
if (write_err)
|
||||
error("cannot feed the input to external filter %s", cmd);
|
||||
|
||||
status = finish_command(&child_process);
|
||||
if (status)
|
||||
error("external filter %s failed %d", cmd, -status);
|
||||
return (write_err || status);
|
||||
}
|
||||
|
||||
static char *apply_filter(const char *path, const char *src,
|
||||
unsigned long *sizep, const char *cmd)
|
||||
{
|
||||
/*
|
||||
* Create a pipeline to have the command filter the buffer's
|
||||
* contents.
|
||||
*
|
||||
* (child --> cmd) --> us
|
||||
*/
|
||||
const int SLOP = 4096;
|
||||
int pipe_feed[2];
|
||||
int status;
|
||||
char *dst;
|
||||
unsigned long dstsize, dstalloc;
|
||||
struct child_process child_process;
|
||||
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
memset(&child_process, 0, sizeof(child_process));
|
||||
|
||||
if (pipe(pipe_feed) < 0) {
|
||||
error("cannot create pipe to run external filter %s", cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fflush(NULL);
|
||||
child_process.pid = fork();
|
||||
if (child_process.pid < 0) {
|
||||
error("cannot fork to run external filter %s", cmd);
|
||||
close(pipe_feed[0]);
|
||||
close(pipe_feed[1]);
|
||||
return NULL;
|
||||
}
|
||||
if (!child_process.pid) {
|
||||
dup2(pipe_feed[1], 1);
|
||||
close(pipe_feed[0]);
|
||||
close(pipe_feed[1]);
|
||||
exit(filter_buffer(path, src, *sizep, cmd));
|
||||
}
|
||||
close(pipe_feed[1]);
|
||||
|
||||
dstalloc = *sizep;
|
||||
dst = xmalloc(dstalloc);
|
||||
dstsize = 0;
|
||||
|
||||
while (1) {
|
||||
ssize_t numread = xread(pipe_feed[0], dst + dstsize,
|
||||
dstalloc - dstsize);
|
||||
|
||||
if (numread <= 0) {
|
||||
if (!numread)
|
||||
break;
|
||||
error("read from external filter %s failed", cmd);
|
||||
free(dst);
|
||||
dst = NULL;
|
||||
break;
|
||||
}
|
||||
dstsize += numread;
|
||||
if (dstalloc <= dstsize + SLOP) {
|
||||
dstalloc = dstsize + SLOP;
|
||||
dst = xrealloc(dst, dstalloc);
|
||||
}
|
||||
}
|
||||
if (close(pipe_feed[0])) {
|
||||
error("read from external filter %s failed", cmd);
|
||||
free(dst);
|
||||
dst = NULL;
|
||||
}
|
||||
|
||||
status = finish_command(&child_process);
|
||||
if (status) {
|
||||
error("external filter %s failed %d", cmd, -status);
|
||||
free(dst);
|
||||
dst = NULL;
|
||||
}
|
||||
|
||||
if (dst)
|
||||
*sizep = dstsize;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static struct convert_driver {
|
||||
const char *name;
|
||||
struct convert_driver *next;
|
||||
char *smudge;
|
||||
char *clean;
|
||||
} *user_convert, **user_convert_tail;
|
||||
|
||||
static int read_convert_config(const char *var, const char *value)
|
||||
{
|
||||
const char *ep, *name;
|
||||
int namelen;
|
||||
struct convert_driver *drv;
|
||||
|
||||
/*
|
||||
* External conversion drivers are configured using
|
||||
* "filter.<name>.variable".
|
||||
*/
|
||||
if (prefixcmp(var, "filter.") || (ep = strrchr(var, '.')) == var + 6)
|
||||
return 0;
|
||||
name = var + 7;
|
||||
namelen = ep - name;
|
||||
for (drv = user_convert; drv; drv = drv->next)
|
||||
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
||||
break;
|
||||
if (!drv) {
|
||||
char *namebuf;
|
||||
drv = xcalloc(1, sizeof(struct convert_driver));
|
||||
namebuf = xmalloc(namelen + 1);
|
||||
memcpy(namebuf, name, namelen);
|
||||
namebuf[namelen] = 0;
|
||||
drv->name = namebuf;
|
||||
drv->next = NULL;
|
||||
*user_convert_tail = drv;
|
||||
user_convert_tail = &(drv->next);
|
||||
}
|
||||
|
||||
ep++;
|
||||
|
||||
/*
|
||||
* filter.<name>.smudge and filter.<name>.clean specifies
|
||||
* the command line:
|
||||
*
|
||||
* command-line
|
||||
*
|
||||
* The command-line will not be interpolated in any way.
|
||||
*/
|
||||
|
||||
if (!strcmp("smudge", ep)) {
|
||||
if (!value)
|
||||
return error("%s: lacks value", var);
|
||||
drv->smudge = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("clean", ep)) {
|
||||
if (!value)
|
||||
return error("%s: lacks value", var);
|
||||
drv->clean = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_convert_check(struct git_attr_check *check)
|
||||
{
|
||||
static struct git_attr *attr_crlf;
|
||||
static struct git_attr *attr_ident;
|
||||
static struct git_attr *attr_filter;
|
||||
|
||||
if (!attr_crlf)
|
||||
if (!attr_crlf) {
|
||||
attr_crlf = git_attr("crlf", 4);
|
||||
check->attr = attr_crlf;
|
||||
attr_ident = git_attr("ident", 5);
|
||||
attr_filter = git_attr("filter", 6);
|
||||
user_convert_tail = &user_convert;
|
||||
git_config(read_convert_config);
|
||||
}
|
||||
check[0].attr = attr_crlf;
|
||||
check[1].attr = attr_ident;
|
||||
check[2].attr = attr_filter;
|
||||
}
|
||||
|
||||
static int count_ident(const char *cp, unsigned long size)
|
||||
{
|
||||
/*
|
||||
* "$ident: 0000000000000000000000000000000000000000 $" <=> "$ident$"
|
||||
*/
|
||||
int cnt = 0;
|
||||
char ch;
|
||||
|
||||
while (size) {
|
||||
ch = *cp++;
|
||||
size--;
|
||||
if (ch != '$')
|
||||
continue;
|
||||
if (size < 6)
|
||||
break;
|
||||
if (memcmp("ident", cp, 5))
|
||||
continue;
|
||||
ch = cp[5];
|
||||
cp += 6;
|
||||
size -= 6;
|
||||
if (ch == '$')
|
||||
cnt++; /* $ident$ */
|
||||
if (ch != ':')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* "$ident: ... "; scan up to the closing dollar sign and discard.
|
||||
*/
|
||||
while (size) {
|
||||
ch = *cp++;
|
||||
size--;
|
||||
if (ch == '$') {
|
||||
cnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static char *ident_to_git(const char *path, const char *src, unsigned long *sizep, int ident)
|
||||
{
|
||||
int cnt;
|
||||
unsigned long size;
|
||||
char *dst, *buf;
|
||||
|
||||
if (!ident)
|
||||
return NULL;
|
||||
size = *sizep;
|
||||
cnt = count_ident(src, size);
|
||||
if (!cnt)
|
||||
return NULL;
|
||||
buf = xmalloc(size);
|
||||
|
||||
for (dst = buf; size; size--) {
|
||||
char ch = *src++;
|
||||
*dst++ = ch;
|
||||
if ((ch == '$') && (6 <= size) &&
|
||||
!memcmp("ident:", src, 6)) {
|
||||
unsigned long rem = size - 6;
|
||||
const char *cp = src + 6;
|
||||
do {
|
||||
ch = *cp++;
|
||||
if (ch == '$')
|
||||
break;
|
||||
rem--;
|
||||
} while (rem);
|
||||
if (!rem)
|
||||
continue;
|
||||
memcpy(dst, "ident$", 6);
|
||||
dst += 6;
|
||||
size -= (cp - src);
|
||||
src = cp;
|
||||
}
|
||||
}
|
||||
|
||||
*sizep = dst - buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *ident_to_worktree(const char *path, const char *src, unsigned long *sizep, int ident)
|
||||
{
|
||||
int cnt;
|
||||
unsigned long size;
|
||||
char *dst, *buf;
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (!ident)
|
||||
return NULL;
|
||||
|
||||
size = *sizep;
|
||||
cnt = count_ident(src, size);
|
||||
if (!cnt)
|
||||
return NULL;
|
||||
|
||||
hash_sha1_file(src, size, "blob", sha1);
|
||||
buf = xmalloc(size + cnt * 43);
|
||||
|
||||
for (dst = buf; size; size--) {
|
||||
const char *cp;
|
||||
char ch = *src++;
|
||||
*dst++ = ch;
|
||||
if ((ch != '$') || (size < 6) || memcmp("ident", src, 5))
|
||||
continue;
|
||||
|
||||
if (src[5] == ':') {
|
||||
/* discard up to but not including the closing $ */
|
||||
unsigned long rem = size - 6;
|
||||
cp = src + 6;
|
||||
do {
|
||||
ch = *cp++;
|
||||
if (ch == '$')
|
||||
break;
|
||||
rem--;
|
||||
} while (rem);
|
||||
if (!rem)
|
||||
continue;
|
||||
size -= (cp - src);
|
||||
} else if (src[5] == '$')
|
||||
cp = src + 5;
|
||||
else
|
||||
continue;
|
||||
|
||||
memcpy(dst, "ident: ", 7);
|
||||
dst += 7;
|
||||
memcpy(dst, sha1_to_hex(sha1), 40);
|
||||
dst += 40;
|
||||
*dst++ = ' ';
|
||||
size -= (cp - src);
|
||||
src = cp;
|
||||
*dst++ = *src++;
|
||||
size--;
|
||||
}
|
||||
|
||||
*sizep = dst - buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int git_path_check_crlf(const char *path, struct git_attr_check *check)
|
||||
@@ -224,26 +562,93 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check)
|
||||
return CRLF_GUESS;
|
||||
}
|
||||
|
||||
static struct convert_driver *git_path_check_convert(const char *path,
|
||||
struct git_attr_check *check)
|
||||
{
|
||||
const char *value = check->value;
|
||||
struct convert_driver *drv;
|
||||
|
||||
if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
|
||||
return NULL;
|
||||
for (drv = user_convert; drv; drv = drv->next)
|
||||
if (!strcmp(value, drv->name))
|
||||
return drv;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int git_path_check_ident(const char *path, struct git_attr_check *check)
|
||||
{
|
||||
const char *value = check->value;
|
||||
|
||||
return !!ATTR_TRUE(value);
|
||||
}
|
||||
|
||||
char *convert_to_git(const char *path, const char *src, unsigned long *sizep)
|
||||
{
|
||||
struct git_attr_check check[1];
|
||||
struct git_attr_check check[3];
|
||||
int crlf = CRLF_GUESS;
|
||||
int ident = 0;
|
||||
char *filter = NULL;
|
||||
char *buf, *buf2;
|
||||
|
||||
setup_convert_check(check);
|
||||
if (!git_checkattr(path, 1, check)) {
|
||||
crlf = git_path_check_crlf(path, check);
|
||||
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
||||
struct convert_driver *drv;
|
||||
crlf = git_path_check_crlf(path, check + 0);
|
||||
ident = git_path_check_ident(path, check + 1);
|
||||
drv = git_path_check_convert(path, check + 2);
|
||||
if (drv && drv->clean)
|
||||
filter = drv->clean;
|
||||
}
|
||||
return crlf_to_git(path, src, sizep, crlf);
|
||||
|
||||
buf = apply_filter(path, src, sizep, filter);
|
||||
|
||||
buf2 = crlf_to_git(path, buf ? buf : src, sizep, crlf);
|
||||
if (buf2) {
|
||||
free(buf);
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
buf2 = ident_to_git(path, buf ? buf : src, sizep, ident);
|
||||
if (buf2) {
|
||||
free(buf);
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep)
|
||||
{
|
||||
struct git_attr_check check[1];
|
||||
struct git_attr_check check[3];
|
||||
int crlf = CRLF_GUESS;
|
||||
int ident = 0;
|
||||
char *filter = NULL;
|
||||
char *buf, *buf2;
|
||||
|
||||
setup_convert_check(check);
|
||||
if (!git_checkattr(path, 1, check)) {
|
||||
crlf = git_path_check_crlf(path, check);
|
||||
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
||||
struct convert_driver *drv;
|
||||
crlf = git_path_check_crlf(path, check + 0);
|
||||
ident = git_path_check_ident(path, check + 1);
|
||||
drv = git_path_check_convert(path, check + 2);
|
||||
if (drv && drv->smudge)
|
||||
filter = drv->smudge;
|
||||
}
|
||||
return crlf_to_worktree(path, src, sizep, crlf);
|
||||
|
||||
buf = ident_to_worktree(path, src, sizep, ident);
|
||||
|
||||
buf2 = crlf_to_worktree(path, buf ? buf : src, sizep, crlf);
|
||||
if (buf2) {
|
||||
free(buf);
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
buf2 = apply_filter(path, buf ? buf : src, sizep, filter);
|
||||
if (buf2) {
|
||||
free(buf);
|
||||
buf = buf2;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
35
date.c
35
date.c
@@ -55,6 +55,32 @@ static struct tm *time_to_tm(unsigned long time, int tz)
|
||||
return gmtime(&t);
|
||||
}
|
||||
|
||||
/*
|
||||
* What value of "tz" was in effect back then at "time" in the
|
||||
* local timezone?
|
||||
*/
|
||||
static int local_tzoffset(unsigned long time)
|
||||
{
|
||||
time_t t, t_local;
|
||||
struct tm tm;
|
||||
int offset, eastwest;
|
||||
|
||||
t = time;
|
||||
localtime_r(&t, &tm);
|
||||
t_local = my_mktime(&tm);
|
||||
|
||||
if (t_local < t) {
|
||||
eastwest = -1;
|
||||
offset = t - t_local;
|
||||
} else {
|
||||
eastwest = 1;
|
||||
offset = t_local - t;
|
||||
}
|
||||
offset /= 60; /* in minutes */
|
||||
offset = (offset % 60) + ((offset / 60) * 100);
|
||||
return offset * eastwest;
|
||||
}
|
||||
|
||||
const char *show_date(unsigned long time, int tz, enum date_mode mode)
|
||||
{
|
||||
struct tm *tm;
|
||||
@@ -102,6 +128,9 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
|
||||
/* Else fall back on absolute format.. */
|
||||
}
|
||||
|
||||
if (mode == DATE_LOCAL)
|
||||
tz = local_tzoffset(time);
|
||||
|
||||
tm = time_to_tm(time, tz);
|
||||
if (!tm)
|
||||
return NULL;
|
||||
@@ -109,12 +138,14 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
|
||||
sprintf(timebuf, "%04d-%02d-%02d", tm->tm_year + 1900,
|
||||
tm->tm_mon + 1, tm->tm_mday);
|
||||
else
|
||||
sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d %+05d",
|
||||
sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
|
||||
weekday_names[tm->tm_wday],
|
||||
month_names[tm->tm_mon],
|
||||
tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
tm->tm_year + 1900, tz);
|
||||
tm->tm_year + 1900,
|
||||
(mode == DATE_LOCAL) ? 0 : ' ',
|
||||
tz);
|
||||
return timebuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Junio C Hamano
|
||||
*/
|
||||
#ifndef _DIFFCORE_H_
|
||||
#define _DIFFCORE_H_
|
||||
#ifndef DIFFCORE_H
|
||||
#define DIFFCORE_H
|
||||
|
||||
/* This header file is internal between diff.c and its diff transformers
|
||||
* (e.g. diffcore-rename, diffcore-pickaxe). Never include this header
|
||||
|
||||
14
entry.c
14
entry.c
@@ -1,7 +1,7 @@
|
||||
#include "cache.h"
|
||||
#include "blob.h"
|
||||
|
||||
static void create_directories(const char *path, struct checkout *state)
|
||||
static void create_directories(const char *path, const struct checkout *state)
|
||||
{
|
||||
int len = strlen(path);
|
||||
char *buf = xmalloc(len + 1);
|
||||
@@ -33,7 +33,7 @@ static void remove_subtree(const char *path)
|
||||
char *name;
|
||||
|
||||
if (!dir)
|
||||
die("cannot opendir %s", path);
|
||||
die("cannot opendir %s (%s)", path, strerror(errno));
|
||||
strcpy(pathbuf, path);
|
||||
name = pathbuf + strlen(path);
|
||||
*name++ = '/';
|
||||
@@ -45,15 +45,15 @@ static void remove_subtree(const char *path)
|
||||
continue;
|
||||
strcpy(name, de->d_name);
|
||||
if (lstat(pathbuf, &st))
|
||||
die("cannot lstat %s", pathbuf);
|
||||
die("cannot lstat %s (%s)", pathbuf, strerror(errno));
|
||||
if (S_ISDIR(st.st_mode))
|
||||
remove_subtree(pathbuf);
|
||||
else if (unlink(pathbuf))
|
||||
die("cannot unlink %s", pathbuf);
|
||||
die("cannot unlink %s (%s)", pathbuf, strerror(errno));
|
||||
}
|
||||
closedir(dir);
|
||||
if (rmdir(path))
|
||||
die("cannot rmdir %s", path);
|
||||
die("cannot rmdir %s (%s)", path, strerror(errno));
|
||||
}
|
||||
|
||||
static int create_file(const char *path, unsigned int mode)
|
||||
@@ -75,7 +75,7 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int write_entry(struct cache_entry *ce, char *path, struct checkout *state, int to_tempfile)
|
||||
static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
|
||||
{
|
||||
int fd;
|
||||
long wrote;
|
||||
@@ -163,7 +163,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
|
||||
return 0;
|
||||
}
|
||||
|
||||
int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
|
||||
int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
|
||||
{
|
||||
static char path[PATH_MAX + 1];
|
||||
struct stat st;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef __GIT_EXEC_CMD_H_
|
||||
#define __GIT_EXEC_CMD_H_
|
||||
#ifndef GIT_EXEC_CMD_H
|
||||
#define GIT_EXEC_CMD_H
|
||||
|
||||
extern void git_set_exec_path(const char *exec_path);
|
||||
extern const char* git_exec_path(void);
|
||||
@@ -8,4 +8,4 @@ extern int execl_git_cmd(const char *cmd, ...);
|
||||
extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]);
|
||||
|
||||
|
||||
#endif /* __GIT_EXEC_CMD_H_ */
|
||||
#endif /* GIT_EXEC_CMD_H */
|
||||
|
||||
@@ -673,7 +673,7 @@ static void fixup_header_footer(void)
|
||||
|
||||
buf = xmalloc(buf_sz);
|
||||
for (;;) {
|
||||
size_t n = xread(pack_fd, buf, buf_sz);
|
||||
ssize_t n = xread(pack_fd, buf, buf_sz);
|
||||
if (!n)
|
||||
break;
|
||||
if (n < 0)
|
||||
@@ -904,6 +904,12 @@ static int store_object(
|
||||
if (e->offset) {
|
||||
duplicate_count_by_type[type]++;
|
||||
return 1;
|
||||
} else if (find_sha1_pack(sha1, packed_git)) {
|
||||
e->type = type;
|
||||
e->pack_id = MAX_PACK_ID;
|
||||
e->offset = 1; /* just not zero! */
|
||||
duplicate_count_by_type[type]++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (last && last->data && last->depth < max_depth) {
|
||||
@@ -1193,6 +1199,8 @@ static int tree_content_set(
|
||||
n = slash1 - p;
|
||||
else
|
||||
n = strlen(p);
|
||||
if (!n)
|
||||
die("Empty path component found in input");
|
||||
|
||||
for (i = 0; i < t->entry_count; i++) {
|
||||
e = t->entries[i];
|
||||
@@ -2021,6 +2029,7 @@ static void import_marks(const char *input_file)
|
||||
e = insert_object(sha1);
|
||||
e->type = type;
|
||||
e->pack_id = MAX_PACK_ID;
|
||||
e->offset = 1; /* just not zero! */
|
||||
}
|
||||
insert_mark(mark, e);
|
||||
}
|
||||
@@ -2086,6 +2095,7 @@ int main(int argc, const char **argv)
|
||||
if (i != argc)
|
||||
usage(fast_import_usage);
|
||||
|
||||
prepare_packed_git();
|
||||
start_packfile();
|
||||
for (;;) {
|
||||
read_next_command();
|
||||
|
||||
@@ -78,7 +78,7 @@ do
|
||||
git-mailinfo $keep_subject $utf8 \
|
||||
.dotest/msg .dotest/patch <$i >.dotest/info || exit 1
|
||||
test -s .dotest/patch || {
|
||||
echo "Patch is empty. Was is split wrong?"
|
||||
echo "Patch is empty. Was it split wrong?"
|
||||
exit 1
|
||||
}
|
||||
git-stripspace < .dotest/msg > .dotest/msg-clean
|
||||
|
||||
@@ -171,13 +171,13 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
|
||||
extern uintmax_t gitstrtoumax(const char *, char **, int);
|
||||
#endif
|
||||
|
||||
extern void release_pack_memory(size_t);
|
||||
extern void release_pack_memory(size_t, int);
|
||||
|
||||
static inline char* xstrdup(const char *str)
|
||||
{
|
||||
char *ret = strdup(str);
|
||||
if (!ret) {
|
||||
release_pack_memory(strlen(str) + 1);
|
||||
release_pack_memory(strlen(str) + 1, -1);
|
||||
ret = strdup(str);
|
||||
if (!ret)
|
||||
die("Out of memory, strdup failed");
|
||||
@@ -191,7 +191,7 @@ static inline void *xmalloc(size_t size)
|
||||
if (!ret && !size)
|
||||
ret = malloc(1);
|
||||
if (!ret) {
|
||||
release_pack_memory(size);
|
||||
release_pack_memory(size, -1);
|
||||
ret = malloc(size);
|
||||
if (!ret && !size)
|
||||
ret = malloc(1);
|
||||
@@ -210,7 +210,7 @@ static inline void *xrealloc(void *ptr, size_t size)
|
||||
if (!ret && !size)
|
||||
ret = realloc(ptr, 1);
|
||||
if (!ret) {
|
||||
release_pack_memory(size);
|
||||
release_pack_memory(size, -1);
|
||||
ret = realloc(ptr, size);
|
||||
if (!ret && !size)
|
||||
ret = realloc(ptr, 1);
|
||||
@@ -226,7 +226,7 @@ static inline void *xcalloc(size_t nmemb, size_t size)
|
||||
if (!ret && (!nmemb || !size))
|
||||
ret = calloc(1, 1);
|
||||
if (!ret) {
|
||||
release_pack_memory(nmemb * size);
|
||||
release_pack_memory(nmemb * size, -1);
|
||||
ret = calloc(nmemb, size);
|
||||
if (!ret && (!nmemb || !size))
|
||||
ret = calloc(1, 1);
|
||||
@@ -243,7 +243,7 @@ static inline void *xmmap(void *start, size_t length,
|
||||
if (ret == MAP_FAILED) {
|
||||
if (!length)
|
||||
return NULL;
|
||||
release_pack_memory(length);
|
||||
release_pack_memory(length, fd);
|
||||
ret = mmap(start, length, prot, flags, fd, offset);
|
||||
if (ret == MAP_FAILED)
|
||||
die("Out of memory? mmap failed: %s", strerror(errno));
|
||||
|
||||
@@ -74,7 +74,7 @@ for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do
|
||||
echo $patch_name
|
||||
(cat $QUILT_PATCHES/$patch_name | git-mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3
|
||||
test -s .dotest/patch || {
|
||||
echo "Patch is empty. Was is split wrong?"
|
||||
echo "Patch is empty. Was it split wrong?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ Options:
|
||||
--quiet Make git-send-email less verbose. One line per email
|
||||
should be all that is output.
|
||||
|
||||
--dry-run Do everything except actually send the emails.
|
||||
|
||||
--envelope-sender Specify the envelope sender used to send the emails.
|
||||
|
||||
EOT
|
||||
exit(1);
|
||||
}
|
||||
@@ -137,6 +141,7 @@ my (@to,@cc,@initial_cc,@bcclist,@xh,
|
||||
my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc,
|
||||
$dry_run) = (1, 0, 0, 0, 0);
|
||||
my $smtp_server;
|
||||
my $envelope_sender;
|
||||
|
||||
# Example reply to:
|
||||
#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
|
||||
@@ -175,6 +180,7 @@ my $rc = GetOptions("from=s" => \$from,
|
||||
"suppress-from" => \$suppress_from,
|
||||
"no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
|
||||
"dry-run" => \$dry_run,
|
||||
"envelope-sender=s" => \$envelope_sender,
|
||||
);
|
||||
|
||||
unless ($rc) {
|
||||
@@ -268,6 +274,7 @@ sub expand_aliases {
|
||||
}
|
||||
|
||||
@to = expand_aliases(@to);
|
||||
@to = (map { sanitize_address_rfc822($_) } @to);
|
||||
@initial_cc = expand_aliases(@initial_cc);
|
||||
@bcclist = expand_aliases(@bcclist);
|
||||
|
||||
@@ -377,7 +384,7 @@ if (@files) {
|
||||
}
|
||||
|
||||
# Variables we set as part of the loop over files
|
||||
our ($message_id, $cc, %mail, $subject, $reply_to, $references, $message);
|
||||
our ($message_id, %mail, $subject, $reply_to, $references, $message);
|
||||
|
||||
sub extract_valid_address {
|
||||
my $address = shift;
|
||||
@@ -418,7 +425,6 @@ sub make_message_id
|
||||
|
||||
|
||||
|
||||
$cc = "";
|
||||
$time = time - scalar $#files;
|
||||
|
||||
sub unquote_rfc2047 {
|
||||
@@ -430,26 +436,37 @@ sub unquote_rfc2047 {
|
||||
return "$_";
|
||||
}
|
||||
|
||||
# If an address contains a . in the name portion, the name must be quoted.
|
||||
sub sanitize_address_rfc822
|
||||
{
|
||||
my ($recipient) = @_;
|
||||
my ($recipient_name) = ($recipient =~ /^(.*?)\s+</);
|
||||
if ($recipient_name && $recipient_name =~ /\./ && $recipient_name !~ /^".*"$/) {
|
||||
my ($name, $addr) = ($recipient =~ /^(.*?)(\s+<.*)/);
|
||||
$recipient = "\"$name\"$addr";
|
||||
}
|
||||
return $recipient;
|
||||
}
|
||||
|
||||
sub send_message
|
||||
{
|
||||
my @recipients = unique_email_list(@to);
|
||||
@cc = (map { sanitize_address_rfc822($_) } @cc);
|
||||
my $to = join (",\n\t", @recipients);
|
||||
@recipients = unique_email_list(@recipients,@cc,@bcclist);
|
||||
@recipients = (map { extract_valid_address($_) } @recipients);
|
||||
my $date = format_2822_time($time++);
|
||||
my $gitversion = '@@GIT_VERSION@@';
|
||||
if ($gitversion =~ m/..GIT_VERSION../) {
|
||||
$gitversion = Git::version();
|
||||
}
|
||||
|
||||
my ($author_name) = ($from =~ /^(.*?)\s+</);
|
||||
if ($author_name && $author_name =~ /\./ && $author_name !~ /^".*"$/) {
|
||||
my ($name, $addr) = ($from =~ /^(.*?)(\s+<.*)/);
|
||||
$from = "\"$name\"$addr";
|
||||
}
|
||||
my $cc = join(", ", unique_email_list(@cc));
|
||||
my $ccline = "";
|
||||
if ($cc ne '') {
|
||||
$ccline = "\nCc: $cc";
|
||||
}
|
||||
$from = sanitize_address_rfc822($from);
|
||||
my $header = "From: $from
|
||||
To: $to${ccline}
|
||||
Subject: $subject
|
||||
@@ -466,22 +483,27 @@ X-Mailer: git-send-email $gitversion
|
||||
$header .= join("\n", @xh) . "\n";
|
||||
}
|
||||
|
||||
my @sendmail_parameters = ('-i', @recipients);
|
||||
my $raw_from = $from;
|
||||
$raw_from = $envelope_sender if (defined $envelope_sender);
|
||||
$raw_from = extract_valid_address($raw_from);
|
||||
unshift (@sendmail_parameters,
|
||||
'-f', $raw_from) if(defined $envelope_sender);
|
||||
|
||||
if ($dry_run) {
|
||||
# We don't want to send the email.
|
||||
} elsif ($smtp_server =~ m#^/#) {
|
||||
my $pid = open my $sm, '|-';
|
||||
defined $pid or die $!;
|
||||
if (!$pid) {
|
||||
exec($smtp_server,'-i',
|
||||
map { extract_valid_address($_) }
|
||||
@recipients) or die $!;
|
||||
exec($smtp_server, @sendmail_parameters) or die $!;
|
||||
}
|
||||
print $sm "$header\n$message";
|
||||
close $sm or die $?;
|
||||
} else {
|
||||
require Net::SMTP;
|
||||
$smtp ||= Net::SMTP->new( $smtp_server );
|
||||
$smtp->mail( $from ) or die $smtp->message;
|
||||
$smtp->mail( $raw_from ) or die $smtp->message;
|
||||
$smtp->to( @recipients ) or die $smtp->message;
|
||||
$smtp->data or die $smtp->message;
|
||||
$smtp->datasend("$header\n$message") or die $smtp->message;
|
||||
@@ -489,13 +511,15 @@ X-Mailer: git-send-email $gitversion
|
||||
$smtp->ok or die "Failed to send $subject\n".$smtp->message;
|
||||
}
|
||||
if ($quiet) {
|
||||
printf "Sent %s\n", $subject;
|
||||
printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
|
||||
} else {
|
||||
print "OK. Log says:\nDate: $date\n";
|
||||
if ($smtp) {
|
||||
print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n");
|
||||
if ($smtp_server !~ m#^/#) {
|
||||
print "Server: $smtp_server\n";
|
||||
print "MAIL FROM:<$raw_from>\n";
|
||||
print "RCPT TO:".join(',',(map { "<$_>" } @recipients))."\n";
|
||||
} else {
|
||||
print "Sendmail: $smtp_server\n";
|
||||
print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
|
||||
}
|
||||
print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
|
||||
if ($smtp) {
|
||||
@@ -590,7 +614,6 @@ foreach my $t (@files) {
|
||||
$message = "From: $author_not_sender\n\n$message";
|
||||
}
|
||||
|
||||
$cc = join(", ", unique_email_list(@cc));
|
||||
|
||||
send_message();
|
||||
|
||||
|
||||
46
git-svn.perl
46
git-svn.perl
@@ -141,6 +141,8 @@ my %cmd = (
|
||||
'color' => \$Git::SVN::Log::color,
|
||||
'pager=s' => \$Git::SVN::Log::pager,
|
||||
} ],
|
||||
'find-rev' => [ \&cmd_find_rev, "Translate between SVN revision numbers and tree-ish",
|
||||
{ } ],
|
||||
'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
|
||||
{ 'merge|m|M' => \$_merge,
|
||||
'verbose|v' => \$_verbose,
|
||||
@@ -428,6 +430,27 @@ sub cmd_dcommit {
|
||||
command_noisy(@finish, $gs->refname);
|
||||
}
|
||||
|
||||
sub cmd_find_rev {
|
||||
my $revision_or_hash = shift;
|
||||
my $result;
|
||||
if ($revision_or_hash =~ /^r\d+$/) {
|
||||
my $head = shift;
|
||||
$head ||= 'HEAD';
|
||||
my @refs;
|
||||
my (undef, undef, undef, $gs) = working_head_info($head, \@refs);
|
||||
unless ($gs) {
|
||||
die "Unable to determine upstream SVN information from ",
|
||||
"$head history\n";
|
||||
}
|
||||
my $desired_revision = substr($revision_or_hash, 1);
|
||||
$result = $gs->rev_db_get($desired_revision);
|
||||
} else {
|
||||
my (undef, $rev, undef) = cmt_metadata($revision_or_hash);
|
||||
$result = $rev;
|
||||
}
|
||||
print "$result\n" if $result;
|
||||
}
|
||||
|
||||
sub cmd_rebase {
|
||||
command_noisy(qw/update-index --refresh/);
|
||||
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
|
||||
@@ -771,19 +794,19 @@ sub cmt_metadata {
|
||||
sub working_head_info {
|
||||
my ($head, $refs) = @_;
|
||||
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
my ($url, $rev, $uuid) = cmt_metadata($_);
|
||||
while (my $hash = <$fh>) {
|
||||
chomp($hash);
|
||||
my ($url, $rev, $uuid) = cmt_metadata($hash);
|
||||
if (defined $url && defined $rev) {
|
||||
if (my $gs = Git::SVN->find_by_url($url)) {
|
||||
my $c = $gs->rev_db_get($rev);
|
||||
if ($c && $c eq $_) {
|
||||
if ($c && $c eq $hash) {
|
||||
close $fh; # break the pipe
|
||||
return ($url, $rev, $uuid, $gs);
|
||||
}
|
||||
}
|
||||
}
|
||||
unshift @$refs, $_ if $refs;
|
||||
unshift @$refs, $hash if $refs;
|
||||
}
|
||||
command_close_pipe($fh, $ctx);
|
||||
(undef, undef, undef, undef);
|
||||
@@ -1064,7 +1087,10 @@ sub init_remote_config {
|
||||
|
||||
sub find_by_url { # repos_root and, path are optional
|
||||
my ($class, $full_url, $repos_root, $path) = @_;
|
||||
|
||||
return undef unless defined $full_url;
|
||||
remove_username($full_url);
|
||||
remove_username($repos_root) if defined $repos_root;
|
||||
my $remotes = read_all_remotes();
|
||||
if (defined $full_url && defined $repos_root && !defined $path) {
|
||||
$path = $full_url;
|
||||
@@ -1072,6 +1098,7 @@ sub find_by_url { # repos_root and, path are optional
|
||||
}
|
||||
foreach my $repo_id (keys %$remotes) {
|
||||
my $u = $remotes->{$repo_id}->{url} or next;
|
||||
remove_username($u);
|
||||
next if defined $repos_root && $repos_root ne $u;
|
||||
|
||||
my $fetch = $remotes->{$repo_id}->{fetch} || {};
|
||||
@@ -1866,11 +1893,14 @@ sub make_log_entry {
|
||||
} elsif ($self->use_svnsync_props) {
|
||||
my $full_url = $self->svnsync->{url};
|
||||
$full_url .= "/$self->{path}" if length $self->{path};
|
||||
remove_username($full_url);
|
||||
my $uuid = $self->svnsync->{uuid};
|
||||
$log_entry{metadata} = "$full_url\@$rev $uuid";
|
||||
$email ||= "$author\@$uuid"
|
||||
} else {
|
||||
$log_entry{metadata} = $self->metadata_url. "\@$rev " .
|
||||
my $url = $self->metadata_url;
|
||||
remove_username($url);
|
||||
$log_entry{metadata} = "$url\@$rev " .
|
||||
$self->ra->get_uuid;
|
||||
$email ||= "$author\@" . $self->ra->get_uuid;
|
||||
}
|
||||
@@ -2439,9 +2469,9 @@ sub close_file {
|
||||
my $got = $md5->hexdigest;
|
||||
die "Checksum mismatch: $path\n",
|
||||
"expected: $exp\n got: $got\n" if ($got ne $exp);
|
||||
seek($fh, 0, 0) or croak $!;
|
||||
sysseek($fh, 0, 0) or croak $!;
|
||||
if ($fb->{mode_b} == 120000) {
|
||||
read($fh, my $buf, 5) == 5 or croak $!;
|
||||
sysread($fh, my $buf, 5) == 5 or croak $!;
|
||||
$buf eq 'link ' or die "$path has mode 120000",
|
||||
"but is not a link\n";
|
||||
}
|
||||
|
||||
1
http.c
1
http.c
@@ -300,6 +300,7 @@ void http_cleanup(void)
|
||||
curl_global_cleanup();
|
||||
|
||||
curl_slist_free_all(pragma_header);
|
||||
pragma_header = NULL;
|
||||
}
|
||||
|
||||
struct active_request_slot *get_active_slot(void)
|
||||
|
||||
2
ident.c
2
ident.c
@@ -201,6 +201,8 @@ const char *fmt_ident(const char *name, const char *email,
|
||||
setup_ident();
|
||||
if (!name)
|
||||
name = git_default_name;
|
||||
if (!email)
|
||||
email = getenv("EMAIL");
|
||||
if (!email)
|
||||
email = git_default_email;
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
if (opt->reflog_info) {
|
||||
show_reflog_message(opt->reflog_info,
|
||||
opt->commit_format == CMIT_FMT_ONELINE,
|
||||
opt->relative_date);
|
||||
opt->date_mode);
|
||||
if (opt->commit_format == CMIT_FMT_ONELINE) {
|
||||
printf("%s", sep);
|
||||
return;
|
||||
@@ -280,7 +280,7 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
*/
|
||||
len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header,
|
||||
sizeof(this_header), abbrev, subject,
|
||||
extra_headers, opt->relative_date);
|
||||
extra_headers, opt->date_mode);
|
||||
|
||||
if (opt->add_signoff)
|
||||
len = append_signoff(this_header, sizeof(this_header), len,
|
||||
|
||||
92
mailmap.c
Normal file
92
mailmap.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "cache.h"
|
||||
#include "path-list.h"
|
||||
#include "mailmap.h"
|
||||
|
||||
int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev)
|
||||
{
|
||||
char buffer[1024];
|
||||
FILE *f = fopen(filename, "r");
|
||||
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
while (fgets(buffer, sizeof(buffer), f) != NULL) {
|
||||
char *end_of_name, *left_bracket, *right_bracket;
|
||||
char *name, *email;
|
||||
int i;
|
||||
if (buffer[0] == '#') {
|
||||
static const char abbrev[] = "# repo-abbrev:";
|
||||
int abblen = sizeof(abbrev) - 1;
|
||||
int len = strlen(buffer);
|
||||
|
||||
if (!repo_abbrev)
|
||||
continue;
|
||||
|
||||
if (len && buffer[len - 1] == '\n')
|
||||
buffer[--len] = 0;
|
||||
if (!strncmp(buffer, abbrev, abblen)) {
|
||||
char *cp;
|
||||
|
||||
if (repo_abbrev)
|
||||
free(*repo_abbrev);
|
||||
*repo_abbrev = xmalloc(len);
|
||||
|
||||
for (cp = buffer + abblen; isspace(*cp); cp++)
|
||||
; /* nothing */
|
||||
strcpy(*repo_abbrev, cp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((left_bracket = strchr(buffer, '<')) == NULL)
|
||||
continue;
|
||||
if ((right_bracket = strchr(left_bracket + 1, '>')) == NULL)
|
||||
continue;
|
||||
if (right_bracket == left_bracket + 1)
|
||||
continue;
|
||||
for (end_of_name = left_bracket; end_of_name != buffer
|
||||
&& isspace(end_of_name[-1]); end_of_name--)
|
||||
/* keep on looking */
|
||||
if (end_of_name == buffer)
|
||||
continue;
|
||||
name = xmalloc(end_of_name - buffer + 1);
|
||||
strlcpy(name, buffer, end_of_name - buffer + 1);
|
||||
email = xmalloc(right_bracket - left_bracket);
|
||||
for (i = 0; i < right_bracket - left_bracket - 1; i++)
|
||||
email[i] = tolower(left_bracket[i + 1]);
|
||||
email[right_bracket - left_bracket - 1] = '\0';
|
||||
path_list_insert(email, map)->util = name;
|
||||
}
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int map_email(struct path_list *map, const char *email, char *name, int maxlen)
|
||||
{
|
||||
char *p;
|
||||
struct path_list_item *item;
|
||||
char buf[1024], *mailbuf;
|
||||
int i;
|
||||
|
||||
/* autocomplete common developers */
|
||||
p = strchr(email, '>');
|
||||
if (!p)
|
||||
return 0;
|
||||
if (p - email + 1 < sizeof(buf))
|
||||
mailbuf = buf;
|
||||
else
|
||||
mailbuf = xmalloc(p - email + 1);
|
||||
|
||||
/* downcase the email address */
|
||||
for (i = 0; i < p - email; i++)
|
||||
mailbuf[i] = tolower(email[i]);
|
||||
mailbuf[i] = 0;
|
||||
item = path_list_lookup(mailbuf, map);
|
||||
if (mailbuf != buf)
|
||||
free(mailbuf);
|
||||
if (item != NULL) {
|
||||
const char *realname = (const char *)item->util;
|
||||
strlcpy(name, realname, maxlen);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
7
mailmap.h
Normal file
7
mailmap.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef MAILMAP_H
|
||||
#define MAILMAP_H
|
||||
|
||||
int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev);
|
||||
int map_email(struct path_list *mailmap, const char *email, char *name, int maxlen);
|
||||
|
||||
#endif
|
||||
@@ -1342,20 +1342,31 @@ static int process_renames(struct path_list *a_renames,
|
||||
mfi = merge_file(o, a, b,
|
||||
a_branch, b_branch);
|
||||
|
||||
if (mfi.merge || !mfi.clean)
|
||||
output(1, "Renamed %s => %s", ren1_src, ren1_dst);
|
||||
if (mfi.merge)
|
||||
output(2, "Auto-merged %s", ren1_dst);
|
||||
if (!mfi.clean) {
|
||||
output(1, "CONFLICT (rename/modify): Merge conflict in %s",
|
||||
ren1_dst);
|
||||
clean_merge = 0;
|
||||
if (mfi.clean &&
|
||||
sha_eq(mfi.sha, ren1->pair->two->sha1) &&
|
||||
mfi.mode == ren1->pair->two->mode)
|
||||
/*
|
||||
* This messaged is part of
|
||||
* t6022 test. If you change
|
||||
* it update the test too.
|
||||
*/
|
||||
output(3, "Skipped %s (merged same as existing)", ren1_dst);
|
||||
else {
|
||||
if (mfi.merge || !mfi.clean)
|
||||
output(1, "Renamed %s => %s", ren1_src, ren1_dst);
|
||||
if (mfi.merge)
|
||||
output(2, "Auto-merged %s", ren1_dst);
|
||||
if (!mfi.clean) {
|
||||
output(1, "CONFLICT (rename/modify): Merge conflict in %s",
|
||||
ren1_dst);
|
||||
clean_merge = 0;
|
||||
|
||||
if (!index_only)
|
||||
update_stages(ren1_dst,
|
||||
o, a, b, 1);
|
||||
if (!index_only)
|
||||
update_stages(ren1_dst,
|
||||
o, a, b, 1);
|
||||
}
|
||||
update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);
|
||||
}
|
||||
update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
object.c
6
object.c
@@ -230,6 +230,11 @@ int object_list_contains(struct object_list *list, struct object *obj)
|
||||
}
|
||||
|
||||
void add_object_array(struct object *obj, const char *name, struct object_array *array)
|
||||
{
|
||||
add_object_array_with_mode(obj, name, array, S_IFINVALID);
|
||||
}
|
||||
|
||||
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode)
|
||||
{
|
||||
unsigned nr = array->nr;
|
||||
unsigned alloc = array->alloc;
|
||||
@@ -243,5 +248,6 @@ void add_object_array(struct object *obj, const char *name, struct object_array
|
||||
}
|
||||
objects[nr].item = obj;
|
||||
objects[nr].name = name;
|
||||
objects[nr].mode = mode;
|
||||
array->nr = ++nr;
|
||||
}
|
||||
|
||||
2
object.h
2
object.h
@@ -17,6 +17,7 @@ struct object_array {
|
||||
struct object_array_entry {
|
||||
struct object *item;
|
||||
const char *name;
|
||||
unsigned mode;
|
||||
} *objects;
|
||||
};
|
||||
|
||||
@@ -77,5 +78,6 @@ int object_list_contains(struct object_list *list, struct object *obj);
|
||||
|
||||
/* Object array handling .. */
|
||||
void add_object_array(struct object *obj, const char *name, struct object_array *array);
|
||||
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode);
|
||||
|
||||
#endif /* OBJECT_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _PATH_LIST_H_
|
||||
#define _PATH_LIST_H_
|
||||
#ifndef PATH_LIST_H
|
||||
#define PATH_LIST_H
|
||||
|
||||
struct path_list_item {
|
||||
char *path;
|
||||
@@ -19,4 +19,4 @@ void path_list_clear(struct path_list *list, int free_items);
|
||||
struct path_list_item *path_list_insert(const char *path, struct path_list *list);
|
||||
struct path_list_item *path_list_lookup(const char *path, struct path_list *list);
|
||||
|
||||
#endif /* _PATH_LIST_H_ */
|
||||
#endif /* PATH_LIST_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef __progress_h__
|
||||
#define __progress_h__
|
||||
#ifndef PROGRESS_H
|
||||
#define PROGRESS_H
|
||||
|
||||
struct progress {
|
||||
const char *prefix;
|
||||
|
||||
252
read-cache.c
252
read-cache.c
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (C) Linus Torvalds, 2005
|
||||
*/
|
||||
#define NO_THE_INDEX_COMPATIBILITY_MACROS
|
||||
#include "cache.h"
|
||||
#include "cache-tree.h"
|
||||
#include "refs.h"
|
||||
@@ -19,14 +20,7 @@
|
||||
#define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
|
||||
#define CACHE_EXT_TREE 0x54524545 /* "TREE" */
|
||||
|
||||
struct cache_entry **active_cache;
|
||||
static time_t index_file_timestamp;
|
||||
unsigned int active_nr, active_alloc, active_cache_changed;
|
||||
|
||||
struct cache_tree *active_cache_tree;
|
||||
|
||||
static void *cache_mmap;
|
||||
static size_t cache_mmap_size;
|
||||
struct index_state the_index;
|
||||
|
||||
/*
|
||||
* This only updates the "non-critical" parts of the directory
|
||||
@@ -196,7 +190,8 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
|
||||
return changed;
|
||||
}
|
||||
|
||||
int ce_match_stat(struct cache_entry *ce, struct stat *st, int options)
|
||||
int ie_match_stat(struct index_state *istate,
|
||||
struct cache_entry *ce, struct stat *st, int options)
|
||||
{
|
||||
unsigned int changed;
|
||||
int ignore_valid = options & 01;
|
||||
@@ -228,8 +223,8 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st, int options)
|
||||
* carefully than others.
|
||||
*/
|
||||
if (!changed &&
|
||||
index_file_timestamp &&
|
||||
index_file_timestamp <= ntohl(ce->ce_mtime.sec)) {
|
||||
istate->timestamp &&
|
||||
istate->timestamp <= ntohl(ce->ce_mtime.sec)) {
|
||||
if (assume_racy_is_modified)
|
||||
changed |= DATA_CHANGED;
|
||||
else
|
||||
@@ -239,10 +234,11 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st, int options)
|
||||
return changed;
|
||||
}
|
||||
|
||||
int ce_modified(struct cache_entry *ce, struct stat *st, int really)
|
||||
int ie_modified(struct index_state *istate,
|
||||
struct cache_entry *ce, struct stat *st, int really)
|
||||
{
|
||||
int changed, changed_fs;
|
||||
changed = ce_match_stat(ce, st, really);
|
||||
changed = ie_match_stat(istate, ce, st, really);
|
||||
if (!changed)
|
||||
return 0;
|
||||
/*
|
||||
@@ -310,15 +306,15 @@ int cache_name_compare(const char *name1, int flags1, const char *name2, int fla
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cache_name_pos(const char *name, int namelen)
|
||||
int index_name_pos(struct index_state *istate, const char *name, int namelen)
|
||||
{
|
||||
int first, last;
|
||||
|
||||
first = 0;
|
||||
last = active_nr;
|
||||
last = istate->cache_nr;
|
||||
while (last > first) {
|
||||
int next = (last + first) >> 1;
|
||||
struct cache_entry *ce = active_cache[next];
|
||||
struct cache_entry *ce = istate->cache[next];
|
||||
int cmp = cache_name_compare(name, namelen, ce->name, ntohs(ce->ce_flags));
|
||||
if (!cmp)
|
||||
return next;
|
||||
@@ -332,27 +328,29 @@ int cache_name_pos(const char *name, int namelen)
|
||||
}
|
||||
|
||||
/* Remove entry, return true if there are more entries to go.. */
|
||||
int remove_cache_entry_at(int pos)
|
||||
int remove_index_entry_at(struct index_state *istate, int pos)
|
||||
{
|
||||
active_cache_changed = 1;
|
||||
active_nr--;
|
||||
if (pos >= active_nr)
|
||||
istate->cache_changed = 1;
|
||||
istate->cache_nr--;
|
||||
if (pos >= istate->cache_nr)
|
||||
return 0;
|
||||
memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
|
||||
memmove(istate->cache + pos,
|
||||
istate->cache + pos + 1,
|
||||
(istate->cache_nr - pos) * sizeof(struct cache_entry *));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remove_file_from_cache(const char *path)
|
||||
int remove_file_from_index(struct index_state *istate, const char *path)
|
||||
{
|
||||
int pos = cache_name_pos(path, strlen(path));
|
||||
int pos = index_name_pos(istate, path, strlen(path));
|
||||
if (pos < 0)
|
||||
pos = -pos-1;
|
||||
while (pos < active_nr && !strcmp(active_cache[pos]->name, path))
|
||||
remove_cache_entry_at(pos);
|
||||
while (pos < istate->cache_nr && !strcmp(istate->cache[pos]->name, path))
|
||||
remove_index_entry_at(istate, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_file_to_cache(const char *path, int verbose)
|
||||
int add_file_to_index(struct index_state *istate, const char *path, int verbose)
|
||||
{
|
||||
int size, namelen;
|
||||
struct stat st;
|
||||
@@ -382,19 +380,19 @@ int add_file_to_cache(const char *path, int verbose)
|
||||
* from it, otherwise assume unexecutable regular file.
|
||||
*/
|
||||
struct cache_entry *ent;
|
||||
int pos = cache_name_pos(path, namelen);
|
||||
int pos = index_name_pos(istate, path, namelen);
|
||||
|
||||
ent = (0 <= pos) ? active_cache[pos] : NULL;
|
||||
ent = (0 <= pos) ? istate->cache[pos] : NULL;
|
||||
ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
|
||||
}
|
||||
|
||||
if (index_path(ce->sha1, path, &st, 1))
|
||||
die("unable to index file %s", path);
|
||||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
|
||||
if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
|
||||
die("unable to add %s to index",path);
|
||||
if (verbose)
|
||||
printf("add '%s'\n", path);
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
cache_tree_invalidate_path(istate->cache_tree, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -498,15 +496,16 @@ inside:
|
||||
* Do we have another file that has the beginning components being a
|
||||
* proper superset of the name we're trying to add?
|
||||
*/
|
||||
static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||
static int has_file_name(struct index_state *istate,
|
||||
const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||
{
|
||||
int retval = 0;
|
||||
int len = ce_namelen(ce);
|
||||
int stage = ce_stage(ce);
|
||||
const char *name = ce->name;
|
||||
|
||||
while (pos < active_nr) {
|
||||
struct cache_entry *p = active_cache[pos++];
|
||||
while (pos < istate->cache_nr) {
|
||||
struct cache_entry *p = istate->cache[pos++];
|
||||
|
||||
if (len >= ce_namelen(p))
|
||||
break;
|
||||
@@ -521,7 +520,7 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac
|
||||
retval = -1;
|
||||
if (!ok_to_replace)
|
||||
break;
|
||||
remove_cache_entry_at(--pos);
|
||||
remove_index_entry_at(istate, --pos);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -530,7 +529,8 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac
|
||||
* Do we have another file with a pathname that is a proper
|
||||
* subset of the name we're trying to add?
|
||||
*/
|
||||
static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||
static int has_dir_name(struct index_state *istate,
|
||||
const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||
{
|
||||
int retval = 0;
|
||||
int stage = ce_stage(ce);
|
||||
@@ -548,7 +548,7 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
||||
}
|
||||
len = slash - name;
|
||||
|
||||
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
|
||||
pos = index_name_pos(istate, name, ntohs(create_ce_flags(len, stage)));
|
||||
if (pos >= 0) {
|
||||
/*
|
||||
* Found one, but not so fast. This could
|
||||
@@ -558,11 +558,11 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
||||
* it is Ok to have a directory at the same
|
||||
* path.
|
||||
*/
|
||||
if (stage || active_cache[pos]->ce_mode) {
|
||||
if (stage || istate->cache[pos]->ce_mode) {
|
||||
retval = -1;
|
||||
if (!ok_to_replace)
|
||||
break;
|
||||
remove_cache_entry_at(pos);
|
||||
remove_index_entry_at(istate, pos);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -574,8 +574,8 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
||||
* already matches the sub-directory, then we know
|
||||
* we're ok, and we can exit.
|
||||
*/
|
||||
while (pos < active_nr) {
|
||||
struct cache_entry *p = active_cache[pos];
|
||||
while (pos < istate->cache_nr) {
|
||||
struct cache_entry *p = istate->cache[pos];
|
||||
if ((ce_namelen(p) <= len) ||
|
||||
(p->name[len] != '/') ||
|
||||
memcmp(p->name, name, len))
|
||||
@@ -602,7 +602,9 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
||||
* from the cache so the caller should recompute the insert position.
|
||||
* When this happens, we return non-zero.
|
||||
*/
|
||||
static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||
static int check_file_directory_conflict(struct index_state *istate,
|
||||
const struct cache_entry *ce,
|
||||
int pos, int ok_to_replace)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -617,28 +619,28 @@ static int check_file_directory_conflict(const struct cache_entry *ce, int pos,
|
||||
* first, since removing those will not change the position
|
||||
* in the array.
|
||||
*/
|
||||
retval = has_file_name(ce, pos, ok_to_replace);
|
||||
retval = has_file_name(istate, ce, pos, ok_to_replace);
|
||||
|
||||
/*
|
||||
* Then check if the path might have a clashing sub-directory
|
||||
* before it.
|
||||
*/
|
||||
return retval + has_dir_name(ce, pos, ok_to_replace);
|
||||
return retval + has_dir_name(istate, ce, pos, ok_to_replace);
|
||||
}
|
||||
|
||||
int add_cache_entry(struct cache_entry *ce, int option)
|
||||
int add_index_entry(struct index_state *istate, struct cache_entry *ce, int option)
|
||||
{
|
||||
int pos;
|
||||
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
|
||||
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
|
||||
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
|
||||
|
||||
pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
|
||||
pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags));
|
||||
|
||||
/* existing match? Just replace it. */
|
||||
if (pos >= 0) {
|
||||
active_cache_changed = 1;
|
||||
active_cache[pos] = ce;
|
||||
istate->cache_changed = 1;
|
||||
istate->cache[pos] = ce;
|
||||
return 0;
|
||||
}
|
||||
pos = -pos-1;
|
||||
@@ -647,10 +649,10 @@ int add_cache_entry(struct cache_entry *ce, int option)
|
||||
* Inserting a merged entry ("stage 0") into the index
|
||||
* will always replace all non-merged entries..
|
||||
*/
|
||||
if (pos < active_nr && ce_stage(ce) == 0) {
|
||||
while (ce_same_name(active_cache[pos], ce)) {
|
||||
if (pos < istate->cache_nr && ce_stage(ce) == 0) {
|
||||
while (ce_same_name(istate->cache[pos], ce)) {
|
||||
ok_to_add = 1;
|
||||
if (!remove_cache_entry_at(pos))
|
||||
if (!remove_index_entry_at(istate, pos))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -661,25 +663,29 @@ int add_cache_entry(struct cache_entry *ce, int option)
|
||||
return -1;
|
||||
|
||||
if (!skip_df_check &&
|
||||
check_file_directory_conflict(ce, pos, ok_to_replace)) {
|
||||
check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
|
||||
if (!ok_to_replace)
|
||||
return error("'%s' appears as both a file and as a directory", ce->name);
|
||||
pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
|
||||
return error("'%s' appears as both a file and as a directory",
|
||||
ce->name);
|
||||
pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags));
|
||||
pos = -pos-1;
|
||||
}
|
||||
|
||||
/* Make sure the array is big enough .. */
|
||||
if (active_nr == active_alloc) {
|
||||
active_alloc = alloc_nr(active_alloc);
|
||||
active_cache = xrealloc(active_cache, active_alloc * sizeof(struct cache_entry *));
|
||||
if (istate->cache_nr == istate->cache_alloc) {
|
||||
istate->cache_alloc = alloc_nr(istate->cache_alloc);
|
||||
istate->cache = xrealloc(istate->cache,
|
||||
istate->cache_alloc * sizeof(struct cache_entry *));
|
||||
}
|
||||
|
||||
/* Add it in.. */
|
||||
active_nr++;
|
||||
if (active_nr > pos)
|
||||
memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
|
||||
active_cache[pos] = ce;
|
||||
active_cache_changed = 1;
|
||||
istate->cache_nr++;
|
||||
if (istate->cache_nr > pos)
|
||||
memmove(istate->cache + pos + 1,
|
||||
istate->cache + pos,
|
||||
(istate->cache_nr - pos - 1) * sizeof(ce));
|
||||
istate->cache[pos] = ce;
|
||||
istate->cache_changed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -694,7 +700,8 @@ int add_cache_entry(struct cache_entry *ce, int option)
|
||||
* For example, you'd want to do this after doing a "git-read-tree",
|
||||
* to link up the stat cache details with the proper files.
|
||||
*/
|
||||
static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, int *err)
|
||||
static struct cache_entry *refresh_cache_ent(struct index_state *istate,
|
||||
struct cache_entry *ce, int really, int *err)
|
||||
{
|
||||
struct stat st;
|
||||
struct cache_entry *updated;
|
||||
@@ -706,7 +713,7 @@ static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
changed = ce_match_stat(ce, &st, really);
|
||||
changed = ie_match_stat(istate, ce, &st, really);
|
||||
if (!changed) {
|
||||
if (really && assume_unchanged &&
|
||||
!(ce->ce_flags & htons(CE_VALID)))
|
||||
@@ -715,7 +722,7 @@ static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really,
|
||||
return ce;
|
||||
}
|
||||
|
||||
if (ce_modified(ce, &st, really)) {
|
||||
if (ie_modified(istate, ce, &st, really)) {
|
||||
if (err)
|
||||
*err = EINVAL;
|
||||
return NULL;
|
||||
@@ -738,7 +745,7 @@ static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really,
|
||||
return updated;
|
||||
}
|
||||
|
||||
int refresh_cache(unsigned int flags)
|
||||
int refresh_index(struct index_state *istate, unsigned int flags)
|
||||
{
|
||||
int i;
|
||||
int has_errors = 0;
|
||||
@@ -747,14 +754,14 @@ int refresh_cache(unsigned int flags)
|
||||
int quiet = (flags & REFRESH_QUIET) != 0;
|
||||
int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
|
||||
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct cache_entry *ce, *new;
|
||||
int cache_errno = 0;
|
||||
|
||||
ce = active_cache[i];
|
||||
ce = istate->cache[i];
|
||||
if (ce_stage(ce)) {
|
||||
while ((i < active_nr) &&
|
||||
! strcmp(active_cache[i]->name, ce->name))
|
||||
while ((i < istate->cache_nr) &&
|
||||
! strcmp(istate->cache[i]->name, ce->name))
|
||||
i++;
|
||||
i--;
|
||||
if (allow_unmerged)
|
||||
@@ -764,7 +771,7 @@ int refresh_cache(unsigned int flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
new = refresh_cache_ent(ce, really, &cache_errno);
|
||||
new = refresh_cache_ent(istate, ce, really, &cache_errno);
|
||||
if (new == ce)
|
||||
continue;
|
||||
if (!new) {
|
||||
@@ -775,7 +782,7 @@ int refresh_cache(unsigned int flags)
|
||||
* means the index is not valid anymore.
|
||||
*/
|
||||
ce->ce_flags &= ~htons(CE_VALID);
|
||||
active_cache_changed = 1;
|
||||
istate->cache_changed = 1;
|
||||
}
|
||||
if (quiet)
|
||||
continue;
|
||||
@@ -783,18 +790,18 @@ int refresh_cache(unsigned int flags)
|
||||
has_errors = 1;
|
||||
continue;
|
||||
}
|
||||
active_cache_changed = 1;
|
||||
/* You can NOT just free active_cache[i] here, since it
|
||||
istate->cache_changed = 1;
|
||||
/* You can NOT just free istate->cache[i] here, since it
|
||||
* might not be necessarily malloc()ed but can also come
|
||||
* from mmap(). */
|
||||
active_cache[i] = new;
|
||||
istate->cache[i] = new;
|
||||
}
|
||||
return has_errors;
|
||||
}
|
||||
|
||||
struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
|
||||
{
|
||||
return refresh_cache_ent(ce, really, NULL);
|
||||
return refresh_cache_ent(&the_index, ce, really, NULL);
|
||||
}
|
||||
|
||||
static int verify_hdr(struct cache_header *hdr, unsigned long size)
|
||||
@@ -814,11 +821,12 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_index_extension(const char *ext, void *data, unsigned long sz)
|
||||
static int read_index_extension(struct index_state *istate,
|
||||
const char *ext, void *data, unsigned long sz)
|
||||
{
|
||||
switch (CACHE_EXT(ext)) {
|
||||
case CACHE_EXT_TREE:
|
||||
active_cache_tree = cache_tree_read(data, sz);
|
||||
istate->cache_tree = cache_tree_read(data, sz);
|
||||
break;
|
||||
default:
|
||||
if (*ext < 'A' || 'Z' < *ext)
|
||||
@@ -830,13 +838,13 @@ static int read_index_extension(const char *ext, void *data, unsigned long sz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_cache(void)
|
||||
int read_index(struct index_state *istate)
|
||||
{
|
||||
return read_cache_from(get_index_file());
|
||||
return read_index_from(istate, get_index_file());
|
||||
}
|
||||
|
||||
/* remember to discard_cache() before reading a different cache! */
|
||||
int read_cache_from(const char *path)
|
||||
int read_index_from(struct index_state *istate, const char *path)
|
||||
{
|
||||
int fd, i;
|
||||
struct stat st;
|
||||
@@ -844,11 +852,11 @@ int read_cache_from(const char *path)
|
||||
struct cache_header *hdr;
|
||||
|
||||
errno = EBUSY;
|
||||
if (cache_mmap)
|
||||
return active_nr;
|
||||
if (istate->mmap)
|
||||
return istate->cache_nr;
|
||||
|
||||
errno = ENOENT;
|
||||
index_file_timestamp = 0;
|
||||
istate->timestamp = 0;
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
@@ -856,33 +864,35 @@ int read_cache_from(const char *path)
|
||||
die("index file open failed (%s)", strerror(errno));
|
||||
}
|
||||
|
||||
if (!fstat(fd, &st)) {
|
||||
cache_mmap_size = xsize_t(st.st_size);
|
||||
errno = EINVAL;
|
||||
if (cache_mmap_size >= sizeof(struct cache_header) + 20)
|
||||
cache_mmap = xmmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
else
|
||||
die("index file smaller than expected");
|
||||
} else
|
||||
if (fstat(fd, &st))
|
||||
die("cannot stat the open index (%s)", strerror(errno));
|
||||
|
||||
errno = EINVAL;
|
||||
istate->mmap_size = xsize_t(st.st_size);
|
||||
if (istate->mmap_size < sizeof(struct cache_header) + 20)
|
||||
die("index file smaller than expected");
|
||||
|
||||
istate->mmap = xmmap(NULL, istate->mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
|
||||
hdr = cache_mmap;
|
||||
if (verify_hdr(hdr, cache_mmap_size) < 0)
|
||||
hdr = istate->mmap;
|
||||
if (verify_hdr(hdr, istate->mmap_size) < 0)
|
||||
goto unmap;
|
||||
|
||||
active_nr = ntohl(hdr->hdr_entries);
|
||||
active_alloc = alloc_nr(active_nr);
|
||||
active_cache = xcalloc(active_alloc, sizeof(struct cache_entry *));
|
||||
istate->cache_nr = ntohl(hdr->hdr_entries);
|
||||
istate->cache_alloc = alloc_nr(istate->cache_nr);
|
||||
istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *));
|
||||
|
||||
offset = sizeof(*hdr);
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = (struct cache_entry *) ((char *) cache_mmap + offset);
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct cache_entry *ce;
|
||||
|
||||
ce = (struct cache_entry *)((char *)(istate->mmap) + offset);
|
||||
offset = offset + ce_size(ce);
|
||||
active_cache[i] = ce;
|
||||
istate->cache[i] = ce;
|
||||
}
|
||||
index_file_timestamp = st.st_mtime;
|
||||
while (offset <= cache_mmap_size - 20 - 8) {
|
||||
istate->timestamp = st.st_mtime;
|
||||
while (offset <= istate->mmap_size - 20 - 8) {
|
||||
/* After an array of active_nr index entries,
|
||||
* there can be arbitrary number of extended
|
||||
* sections, each of which is prefixed with
|
||||
@@ -890,35 +900,37 @@ int read_cache_from(const char *path)
|
||||
* in 4-byte network byte order.
|
||||
*/
|
||||
unsigned long extsize;
|
||||
memcpy(&extsize, (char *) cache_mmap + offset + 4, 4);
|
||||
memcpy(&extsize, (char *)(istate->mmap) + offset + 4, 4);
|
||||
extsize = ntohl(extsize);
|
||||
if (read_index_extension(((const char *) cache_mmap) + offset,
|
||||
(char *) cache_mmap + offset + 8,
|
||||
if (read_index_extension(istate,
|
||||
((const char *) (istate->mmap)) + offset,
|
||||
(char *) (istate->mmap) + offset + 8,
|
||||
extsize) < 0)
|
||||
goto unmap;
|
||||
offset += 8;
|
||||
offset += extsize;
|
||||
}
|
||||
return active_nr;
|
||||
return istate->cache_nr;
|
||||
|
||||
unmap:
|
||||
munmap(cache_mmap, cache_mmap_size);
|
||||
munmap(istate->mmap, istate->mmap_size);
|
||||
errno = EINVAL;
|
||||
die("index file corrupt");
|
||||
}
|
||||
|
||||
int discard_cache(void)
|
||||
int discard_index(struct index_state *istate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
active_nr = active_cache_changed = 0;
|
||||
index_file_timestamp = 0;
|
||||
cache_tree_free(&active_cache_tree);
|
||||
if (cache_mmap == NULL)
|
||||
istate->cache_nr = 0;
|
||||
istate->cache_changed = 0;
|
||||
istate->timestamp = 0;
|
||||
cache_tree_free(&(istate->cache_tree));
|
||||
if (istate->mmap == NULL)
|
||||
return 0;
|
||||
ret = munmap(cache_mmap, cache_mmap_size);
|
||||
cache_mmap = NULL;
|
||||
cache_mmap_size = 0;
|
||||
ret = munmap(istate->mmap, istate->mmap_size);
|
||||
istate->mmap = NULL;
|
||||
istate->mmap_size = 0;
|
||||
|
||||
/* no need to throw away allocated active_cache */
|
||||
return ret;
|
||||
@@ -1037,11 +1049,13 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
|
||||
}
|
||||
}
|
||||
|
||||
int write_cache(int newfd, struct cache_entry **cache, int entries)
|
||||
int write_index(struct index_state *istate, int newfd)
|
||||
{
|
||||
SHA_CTX c;
|
||||
struct cache_header hdr;
|
||||
int i, removed;
|
||||
struct cache_entry **cache = istate->cache;
|
||||
int entries = istate->cache_nr;
|
||||
|
||||
for (i = removed = 0; i < entries; i++)
|
||||
if (!cache[i]->ce_mode)
|
||||
@@ -1059,17 +1073,17 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
|
||||
struct cache_entry *ce = cache[i];
|
||||
if (!ce->ce_mode)
|
||||
continue;
|
||||
if (index_file_timestamp &&
|
||||
index_file_timestamp <= ntohl(ce->ce_mtime.sec))
|
||||
if (istate->timestamp &&
|
||||
istate->timestamp <= ntohl(ce->ce_mtime.sec))
|
||||
ce_smudge_racily_clean_entry(ce);
|
||||
if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write extension data here */
|
||||
if (active_cache_tree) {
|
||||
if (istate->cache_tree) {
|
||||
unsigned long sz;
|
||||
void *data = cache_tree_write(active_cache_tree, &sz);
|
||||
void *data = cache_tree_write(istate->cache_tree, &sz);
|
||||
if (data &&
|
||||
!write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) &&
|
||||
!ce_write(&c, newfd, data, sz))
|
||||
|
||||
30
revision.c
30
revision.c
@@ -115,10 +115,15 @@ void mark_parents_uninteresting(struct commit *commit)
|
||||
}
|
||||
|
||||
void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
|
||||
{
|
||||
add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
|
||||
}
|
||||
|
||||
void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
|
||||
{
|
||||
if (revs->no_walk && (obj->flags & UNINTERESTING))
|
||||
die("object ranges do not make sense when not walking revisions");
|
||||
add_object_array(obj, name, &revs->pending);
|
||||
add_object_array_with_mode(obj, name, &revs->pending, mode);
|
||||
if (revs->reflog_info && obj->type == OBJ_COMMIT)
|
||||
add_reflog_for_walk(revs->reflog_info,
|
||||
(struct commit *)obj, name);
|
||||
@@ -723,6 +728,7 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
|
||||
int flags,
|
||||
int cant_be_filename)
|
||||
{
|
||||
unsigned mode;
|
||||
char *dotdot;
|
||||
struct object *object;
|
||||
unsigned char sha1[20];
|
||||
@@ -796,12 +802,12 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
|
||||
local_flags = UNINTERESTING;
|
||||
arg++;
|
||||
}
|
||||
if (get_sha1(arg, sha1))
|
||||
if (get_sha1_with_mode(arg, sha1, &mode))
|
||||
return -1;
|
||||
if (!cant_be_filename)
|
||||
verify_non_filename(revs->prefix, arg);
|
||||
object = get_reference(revs, arg, sha1, flags ^ local_flags);
|
||||
add_pending_object(revs, object, arg);
|
||||
add_pending_object_with_mode(revs, object, arg, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1105,7 +1111,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--relative-date")) {
|
||||
revs->relative_date = 1;
|
||||
revs->date_mode = DATE_RELATIVE;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--date=", 7)) {
|
||||
if (!strcmp(arg + 7, "relative"))
|
||||
revs->date_mode = DATE_RELATIVE;
|
||||
else if (!strcmp(arg + 7, "local"))
|
||||
revs->date_mode = DATE_LOCAL;
|
||||
else if (!strcmp(arg + 7, "default"))
|
||||
revs->date_mode = DATE_NORMAL;
|
||||
else
|
||||
die("unknown date format %s", arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1177,10 +1194,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
if (def && !revs->pending.nr) {
|
||||
unsigned char sha1[20];
|
||||
struct object *object;
|
||||
if (get_sha1(def, sha1))
|
||||
unsigned mode;
|
||||
if (get_sha1_with_mode(def, sha1, &mode))
|
||||
die("bad default revision '%s'", def);
|
||||
object = get_reference(revs, def, sha1, 0);
|
||||
add_pending_object(revs, object, def);
|
||||
add_pending_object_with_mode(revs, object, def, mode);
|
||||
}
|
||||
|
||||
if (revs->topo_order)
|
||||
|
||||
@@ -63,8 +63,8 @@ struct rev_info {
|
||||
|
||||
/* Format info */
|
||||
unsigned int shown_one:1,
|
||||
abbrev_commit:1,
|
||||
relative_date:1;
|
||||
abbrev_commit:1;
|
||||
enum date_mode date_mode;
|
||||
|
||||
const char **ignore_packed; /* pretend objects in these are unpacked */
|
||||
int num_ignore_packed;
|
||||
@@ -131,5 +131,6 @@ extern void add_object(struct object *obj,
|
||||
const char *name);
|
||||
|
||||
extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
|
||||
extern void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode);
|
||||
|
||||
#endif
|
||||
|
||||
10
sha1_file.c
10
sha1_file.c
@@ -557,7 +557,7 @@ static void scan_windows(struct packed_git *p,
|
||||
}
|
||||
}
|
||||
|
||||
static int unuse_one_window(struct packed_git *current)
|
||||
static int unuse_one_window(struct packed_git *current, int keep_fd)
|
||||
{
|
||||
struct packed_git *p, *lru_p = NULL;
|
||||
struct pack_window *lru_w = NULL, *lru_l = NULL;
|
||||
@@ -573,7 +573,7 @@ static int unuse_one_window(struct packed_git *current)
|
||||
lru_l->next = lru_w->next;
|
||||
else {
|
||||
lru_p->windows = lru_w->next;
|
||||
if (!lru_p->windows && lru_p != current) {
|
||||
if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
|
||||
close(lru_p->pack_fd);
|
||||
lru_p->pack_fd = -1;
|
||||
}
|
||||
@@ -585,10 +585,10 @@ static int unuse_one_window(struct packed_git *current)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void release_pack_memory(size_t need)
|
||||
void release_pack_memory(size_t need, int fd)
|
||||
{
|
||||
size_t cur = pack_mapped;
|
||||
while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
|
||||
while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
|
||||
; /* nothing */
|
||||
}
|
||||
|
||||
@@ -723,7 +723,7 @@ unsigned char* use_pack(struct packed_git *p,
|
||||
win->len = (size_t)len;
|
||||
pack_mapped += win->len;
|
||||
while (packed_git_limit < pack_mapped
|
||||
&& unuse_one_window(p))
|
||||
&& unuse_one_window(p, p->pack_fd))
|
||||
; /* nothing */
|
||||
win->base = xmmap(NULL, win->len,
|
||||
PROT_READ, MAP_PRIVATE,
|
||||
|
||||
11
sha1_name.c
11
sha1_name.c
@@ -643,11 +643,17 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
|
||||
*/
|
||||
int get_sha1(const char *name, unsigned char *sha1)
|
||||
{
|
||||
int ret, bracket_depth;
|
||||
unsigned unused;
|
||||
return get_sha1_with_mode(name, sha1, &unused);
|
||||
}
|
||||
|
||||
int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
|
||||
{
|
||||
int ret, bracket_depth;
|
||||
int namelen = strlen(name);
|
||||
const char *cp;
|
||||
|
||||
*mode = S_IFINVALID;
|
||||
prepare_alt_odb();
|
||||
ret = get_sha1_1(name, namelen, sha1);
|
||||
if (!ret)
|
||||
@@ -685,6 +691,7 @@ int get_sha1(const char *name, unsigned char *sha1)
|
||||
break;
|
||||
if (ce_stage(ce) == stage) {
|
||||
hashcpy(sha1, ce->sha1);
|
||||
*mode = ntohl(ce->ce_mode);
|
||||
return 0;
|
||||
}
|
||||
pos++;
|
||||
@@ -703,7 +710,7 @@ int get_sha1(const char *name, unsigned char *sha1)
|
||||
unsigned char tree_sha1[20];
|
||||
if (!get_sha1_1(name, cp-name, tree_sha1))
|
||||
return get_tree_entry(tree_sha1, cp+1, sha1,
|
||||
&unused);
|
||||
mode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
48
t/t0021-conversion.sh
Executable file
48
t/t0021-conversion.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='blob conversion via gitattributes'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
cat <<\EOF >rot13.sh
|
||||
tr '[a-zA-Z]' '[n-za-mN-ZA-M]'
|
||||
EOF
|
||||
chmod +x rot13.sh
|
||||
|
||||
test_expect_success setup '
|
||||
git config filter.rot13.smudge ./rot13.sh &&
|
||||
git config filter.rot13.clean ./rot13.sh &&
|
||||
|
||||
{
|
||||
echo "*.t filter=rot13"
|
||||
echo "*.i ident"
|
||||
} >.gitattributes &&
|
||||
|
||||
{
|
||||
echo a b c d e f g h i j k l m
|
||||
echo n o p q r s t u v w x y z
|
||||
echo '\''$ident$'\''
|
||||
} >test &&
|
||||
cat test >test.t &&
|
||||
cat test >test.o &&
|
||||
cat test >test.i &&
|
||||
git add test test.t test.i &&
|
||||
rm -f test test.t test.i &&
|
||||
git checkout -- test test.t test.i
|
||||
'
|
||||
|
||||
script='s/^\$ident: \([0-9a-f]*\) \$/\1/p'
|
||||
|
||||
test_expect_success check '
|
||||
|
||||
cmp test.o test &&
|
||||
cmp test.o test.t &&
|
||||
|
||||
# ident should be stripped in the repository
|
||||
git diff --raw --exit-code :test :test.i &&
|
||||
id=$(git rev-parse --verify :test) &&
|
||||
embedded=$(sed -ne "$script" test.i) &&
|
||||
test "z$id" = "z$embedded"
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -47,6 +47,8 @@ git branch white &&
|
||||
git branch red &&
|
||||
git branch blue &&
|
||||
git branch yellow &&
|
||||
git branch change &&
|
||||
git branch change+rename &&
|
||||
|
||||
sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
|
||||
mv A+ A &&
|
||||
@@ -77,6 +79,17 @@ rm -f A M &&
|
||||
git update-index --add --remove A C M N &&
|
||||
git commit -m "blue renames A->C, M->N" &&
|
||||
|
||||
git checkout change &&
|
||||
sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
|
||||
mv A+ A &&
|
||||
git commit -q -a -m "changed" &&
|
||||
|
||||
git checkout change+rename &&
|
||||
sed -e "/^g /s/.*/g : changed line/" <A >B &&
|
||||
rm A &&
|
||||
git update-index --add B &&
|
||||
git commit -q -a -m "changed and renamed" &&
|
||||
|
||||
git checkout master'
|
||||
|
||||
test_expect_success 'pull renaming branch into unrenaming one' \
|
||||
@@ -318,4 +331,14 @@ test_expect_success 'interference with untracked working tree file' '
|
||||
git reset --hard anchor
|
||||
'
|
||||
|
||||
test_expect_success 'merge of identical changes in a renamed file' '
|
||||
rm -f A M N
|
||||
git reset --hard &&
|
||||
git checkout change+rename &&
|
||||
GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
|
||||
git reset --hard HEAD^ &&
|
||||
git checkout change &&
|
||||
GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -16,6 +16,7 @@ unset AUTHOR_EMAIL
|
||||
unset AUTHOR_NAME
|
||||
unset COMMIT_AUTHOR_EMAIL
|
||||
unset COMMIT_AUTHOR_NAME
|
||||
unset EMAIL
|
||||
unset GIT_ALTERNATE_OBJECT_DIRECTORIES
|
||||
unset GIT_AUTHOR_DATE
|
||||
GIT_AUTHOR_EMAIL=author@example.com
|
||||
@@ -36,6 +37,10 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
|
||||
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
|
||||
export EDITOR VISUAL
|
||||
|
||||
# Protect ourselves from common misconfiguration to export
|
||||
# CDPATH into the environment
|
||||
unset CDPATH
|
||||
|
||||
case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
|
||||
1|2|true)
|
||||
echo "* warning: Some tests will not work if GIT_TRACE" \
|
||||
|
||||
Reference in New Issue
Block a user