mirror of
https://github.com/git/git.git
synced 2026-04-01 20:40:08 +02:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
@@ -17,6 +17,7 @@ DOC_HTML=$(MAN_HTML)
|
||||
ARTICLES = howto-index
|
||||
ARTICLES += everyday
|
||||
ARTICLES += git-tools
|
||||
ARTICLES += git-bisect-lk2009
|
||||
# with their own formatting rules.
|
||||
SP_ARTICLES = howto/revert-branch-rebase howto/using-merge-subtree user-manual
|
||||
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
|
||||
|
||||
32
Documentation/RelNotes-1.6.5.4.txt
Normal file
32
Documentation/RelNotes-1.6.5.4.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
Git v1.6.5.4 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.6.5.3
|
||||
--------------------
|
||||
|
||||
* "git help" (without argument) used to check if you are in a directory
|
||||
under git control. There was no breakage in behaviour per-se, but this
|
||||
was unnecessary.
|
||||
|
||||
* "git prune-packed" gave progress output even when its standard error is
|
||||
not connected to a terminal; this caused cron jobs that run it to
|
||||
produce crufts.
|
||||
|
||||
* "git pack-objects --all-progress" is an option to ask progress output
|
||||
from write-object phase _if_ progress output were to be produced, and
|
||||
shouldn't have forced the progress output.
|
||||
|
||||
* "git apply -p<n> --directory=<elsewhere>" did not work well for a
|
||||
non-default value of n.
|
||||
|
||||
* "git merge foo HEAD" was misparsed as an old-style invocation of the
|
||||
command and produced a confusing error message. As it does not specify
|
||||
any other branch to merge, it shouldn't be mistaken as such. We will
|
||||
remove the old style "git merge <message> HEAD <commit>..." syntax in
|
||||
future versions, but not in this release,
|
||||
|
||||
* "git merge -m <message> <branch>..." added the standard merge message
|
||||
on its own after user-supplied message, which should have overrided the
|
||||
standard one.
|
||||
|
||||
Other minor documentation updates are included.
|
||||
@@ -1,39 +1,106 @@
|
||||
Git v1.6.6 Release Notes
|
||||
========================
|
||||
|
||||
In this release, "git fsck" defaults to "git fsck --full" and checks
|
||||
packfiles, and because of this it will take much longer to complete
|
||||
than before. If you prefer a quicker check only on loose objects (the
|
||||
old default), you can say "git fsck --no-full". This has been
|
||||
supported by 1.5.4 and newer versions of git, so it is safe to write
|
||||
it in your script even if you use slightly older git on some of your
|
||||
machines.
|
||||
Notes on behaviour change
|
||||
-------------------------
|
||||
|
||||
In git 1.7.0, which is planned to be the release after 1.6.6, "git
|
||||
push" into a branch that is currently checked out will be refused by
|
||||
default.
|
||||
* In this release, "git fsck" defaults to "git fsck --full" and
|
||||
checks packfiles, and because of this it will take much longer to
|
||||
complete than before. If you prefer a quicker check only on loose
|
||||
objects (the old default), you can say "git fsck --no-full". This
|
||||
has been supported by 1.5.4 and newer versions of git, so it is
|
||||
safe to write it in your script even if you use slightly older git
|
||||
on some of your machines.
|
||||
|
||||
You can choose what should happen upon such a push by setting the
|
||||
configuration variable receive.denyCurrentBranch in the receiving
|
||||
repository.
|
||||
Preparing yourselves for compatibility issues in 1.7.0
|
||||
------------------------------------------------------
|
||||
|
||||
Also, "git push $there :$killed" to delete the branch $killed in a remote
|
||||
repository $there, when $killed branch is the current branch pointed at by
|
||||
its HEAD, will be refused by default.
|
||||
In git 1.7.0, which is planned to be the release after 1.6.6, there will
|
||||
be a handful of behaviour changes that will break backward compatibility.
|
||||
|
||||
You can choose what should happen upon such a push by setting the
|
||||
configuration variable receive.denyDeleteCurrent in the receiving
|
||||
repository.
|
||||
These changes were discussed long time ago and existing behaviours have
|
||||
been identified as more problematic to the userbase than keeping them for
|
||||
the sake of backward compatibility.
|
||||
|
||||
To ease the transition plan, the receiving repository of such a
|
||||
push running this release will issue a big warning when the
|
||||
configuration variable is missing. Please refer to:
|
||||
When necessary, transition strategy for existing users has been designed
|
||||
not to force them running around setting configuration variables and
|
||||
updating their scripts in order to either keep the traditional behaviour
|
||||
or use the new behaviour on the day their sysadmin decides to install
|
||||
the new version of git. When we switched from "git-foo" to "git foo" in
|
||||
1.6.0, even though the change had been advertised and the transition
|
||||
guide had been provided for a very long time, the users procrastinated
|
||||
during the entire transtion period, and ended up panicking on the day
|
||||
their sysadmins updated their git installation. We tried very hard to
|
||||
avoid repeating that unpleasantness.
|
||||
|
||||
http://git.or.cz/gitwiki/GitFaq#non-bare
|
||||
http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
|
||||
For changes decided to be in 1.7.0, we have been much louder to strongly
|
||||
discourage such procrastination. If you have been using recent versions
|
||||
of git, you would have already seen warnings issued when you exercised
|
||||
features whose behaviour will change, with the instruction on how to
|
||||
keep the existing behaviour if you want to. You hopefully should be
|
||||
well prepared already.
|
||||
|
||||
Of course, we have also given "this and that will change in 1.7.0;
|
||||
prepare yourselves" warnings in the release notes and announcement
|
||||
messages. Let's see how well users will fare this time.
|
||||
|
||||
* "git push" into a branch that is currently checked out (i.e. pointed by
|
||||
HEAD in a repository that is not bare) will be refused by default.
|
||||
|
||||
Similarly, "git push $there :$killed" to delete the branch $killed
|
||||
in a remote repository $there, when $killed branch is the current
|
||||
branch pointed at by its HEAD, will be refused by default.
|
||||
|
||||
Setting the configuration variables receive.denyCurrentBranch and
|
||||
receive.denyDeleteCurrent to 'ignore' in the receiving repository
|
||||
can be used to override these safety features. Versions of git
|
||||
since 1.6.2 have issued a loud warning when you tried to do them
|
||||
without setting the configuration, so repositories of people who
|
||||
still need to be able to perform such a push should already have
|
||||
been future proofed.
|
||||
|
||||
Please refer to:
|
||||
|
||||
http://git.or.cz/gitwiki/GitFaq#non-bare
|
||||
http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
|
||||
|
||||
for more details on the reason why this change is needed and the
|
||||
transition process that already took place so far.
|
||||
|
||||
* "git send-email" will not make deep threads by default when sending a
|
||||
patch series with more than two messages. All messages will be sent
|
||||
as a reply to the first message, i.e. cover letter. Git 1.6.6 (this
|
||||
release) will issue a warning about the upcoming default change, when
|
||||
it uses the traditional "deep threading" behaviour as the built-in
|
||||
default. To squelch the warning but still use the "deep threading"
|
||||
behaviour, give --chain-reply-to option or set sendemail.chainreplyto
|
||||
to true.
|
||||
|
||||
It has been possible to configure send-email to send "shallow thread"
|
||||
by setting sendemail.chainreplyto configuration variable to false.
|
||||
The only thing 1.7.0 release will do is to change the default when
|
||||
you haven't configured that variable.
|
||||
|
||||
* "git status" will not be "git commit --dry-run". This change does not
|
||||
affect you if you run the command without pathspec.
|
||||
|
||||
Nobody sane found the current behaviour of "git status Makefile" useful
|
||||
nor meaningful, and it confused users. "git commit --dry-run" has been
|
||||
provided as a way to get the current behaviour of this command since
|
||||
1.6.5.
|
||||
|
||||
* "git diff" traditionally treated various "ignore whitespace" options
|
||||
only as a way to filter the patch output. "git diff --exit-code -b"
|
||||
exited with non-zero status even if all changes were about changing the
|
||||
ammount of whitespace and nothing else. and "git diff -b" showed the
|
||||
"diff --git" header line for such a change without patch text.
|
||||
|
||||
In 1.7.0, the "ignore whitespaces" will affect the semantics of the
|
||||
diff operation itself. A change that does not affect anything but
|
||||
whitespaces will be reported with zero exit status when run with
|
||||
--exit-code, and there will not be "diff --git" header for such a
|
||||
change.
|
||||
|
||||
for more details on the reason why this change is needed and the
|
||||
transition plan.
|
||||
|
||||
Updates since v1.6.5
|
||||
--------------------
|
||||
@@ -71,11 +138,25 @@ Updates since v1.6.5
|
||||
is only one remote tracking branch "frotz" is taken as a request to
|
||||
start the named branch at the corresponding remote tracking branch.
|
||||
|
||||
* "git commit -c/-C/--amend" can be told with a new "--reset-author" option
|
||||
to ignore authorship information in the commit it is taking the message
|
||||
from.
|
||||
|
||||
* "git describe" can be told to add "-dirty" suffix with "--dirty" option.
|
||||
|
||||
* "git diff" learned --submodule option to show a list of one-line logs
|
||||
instead of differences between the commit object names.
|
||||
|
||||
* "git diff" learned to honor diff.color.func configuration to paint
|
||||
function name hint printed on the hunk header "@@ -j,k +l,m @@" line
|
||||
in the specified color.
|
||||
|
||||
* "git fetch" learned --all and --multiple options, to run fetch from
|
||||
many repositories, and --prune option to remove remote tracking
|
||||
branches that went stale. These make "git remote update" and "git
|
||||
remote prune" less necessary (there is no plan to remove "remote
|
||||
update" nor "remote prune", though).
|
||||
|
||||
* "git fsck" by default checks the packfiles (i.e. "--full" is the
|
||||
default); you can turn it off with "git fsck --no-full".
|
||||
|
||||
@@ -88,6 +169,9 @@ Updates since v1.6.5
|
||||
|
||||
* "git log --decorate" shows the location of HEAD as well.
|
||||
|
||||
* "git log" and "git rev-list" learned to take revs and pathspecs from
|
||||
the standard input with the new "--stdin" option.
|
||||
|
||||
* "--pretty=format" option to "log" family of commands learned:
|
||||
|
||||
. to wrap text with the "%w()" specifier.
|
||||
@@ -98,6 +182,10 @@ Updates since v1.6.5
|
||||
* "git merge" (and "git pull") learned --ff-only option to make it fail
|
||||
if the merge does not result in a fast-forward.
|
||||
|
||||
* The ancient "git merge <message> HEAD <branch>..." syntax will be
|
||||
removed in later versions of git. A warning is given and tells
|
||||
users to use the "git merge -m <message> <branch>..." instead.
|
||||
|
||||
* "git mergetool" learned to use p4merge.
|
||||
|
||||
* "git rebase -i" learned "reword" that acts like "edit" but immediately
|
||||
@@ -105,11 +193,21 @@ Updates since v1.6.5
|
||||
the shell, which is done by "edit" to give an opportunity to tweak the
|
||||
contents.
|
||||
|
||||
* "git send-email" can be told with "--envelope-sender=auto" to use the
|
||||
same address as "From:" address as the envelope sender address.
|
||||
|
||||
* "git send-email" will issue a warning when it defaults to the
|
||||
--chain-reply-to behaviour without being told by the user and
|
||||
instructs to prepare for the change of the default in 1.7.0 release.
|
||||
|
||||
* In "git submodule add <repository> <path>", <path> is now optional and
|
||||
inferred from <repository> the same way "git clone <repository>" does.
|
||||
|
||||
* "git svn" learned to read SVN 1.5+ and SVK merge tickets.
|
||||
|
||||
* "gitweb" can optionally render its "blame" output incrementally (this
|
||||
requires JavaScript on the client side).
|
||||
|
||||
* Author names shown in gitweb output are links to search commits by the
|
||||
author.
|
||||
|
||||
@@ -122,8 +220,24 @@ Fixes since v1.6.5
|
||||
All of the fixes in v1.6.5.X maintenance series are included in this
|
||||
release, unless otherwise noted.
|
||||
|
||||
* Enumeration of available merge strategies iterated over the list of
|
||||
commands in a wrong way, sometimes producing an incorrect result.
|
||||
Will backport by merging ed87465 (builtin-merge.c: call
|
||||
exclude_cmds() correctly., 2009-11-25).
|
||||
|
||||
* "git format-patch revisions... -- path" issued an incorrect error
|
||||
message that suggested to use "--" on the command line when path
|
||||
does not exist in the current work tree (it is a separate matter if
|
||||
it makes sense to limit format-patch with pathspecs like that
|
||||
without using the --full-diff option). Will backport by merging
|
||||
7e93d3b (format-patch: add test for parsing of "--", 2009-11-26).
|
||||
|
||||
* "git shortlog" did not honor the "encoding" header embedded in the
|
||||
commit object like "git log" did. Will backport by merging 79f7ca0
|
||||
(shortlog: respect commit encoding, 2009-11-25).
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
echo O=$(git describe master)
|
||||
O=v1.6.5.3-337-gf341feb
|
||||
O=v1.6.6-rc0-119-gc0ecb07
|
||||
git shortlog --no-merges $O..master --not maint
|
||||
|
||||
@@ -126,12 +126,20 @@ advice.*::
|
||||
Directions on how to stage/unstage/add shown in the
|
||||
output of linkgit:git-status[1] and the template shown
|
||||
when writing commit messages. Default: true.
|
||||
commitBeforeMerge::
|
||||
Advice shown when linkgit:git-merge[1] refuses to
|
||||
merge to avoid overwritting local changes.
|
||||
Default: true.
|
||||
--
|
||||
|
||||
core.fileMode::
|
||||
If false, the executable bit differences between the index and
|
||||
the working copy are ignored; useful on broken filesystems like FAT.
|
||||
See linkgit:git-update-index[1]. True by default.
|
||||
See linkgit:git-update-index[1].
|
||||
+
|
||||
The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
|
||||
will probe and set core.fileMode false if appropriate when the
|
||||
repository is created.
|
||||
|
||||
core.ignoreCygwinFSTricks::
|
||||
This option is only used by Cygwin implementation of Git. If false,
|
||||
@@ -144,6 +152,18 @@ core.ignoreCygwinFSTricks::
|
||||
is true, in which case ignoreCygwinFSTricks is ignored as Cygwin's
|
||||
POSIX emulation is required to support core.filemode.
|
||||
|
||||
core.ignorecase::
|
||||
If true, this option enables various workarounds to enable
|
||||
git to work better on filesystems that are not case sensitive,
|
||||
like FAT. For example, if a directory listing finds
|
||||
"makefile" when git expects "Makefile", git will assume
|
||||
it is really the same file, and continue to remember it as
|
||||
"Makefile".
|
||||
+
|
||||
The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
|
||||
will probe and set core.ignorecase true if appropriate when the repository
|
||||
is created.
|
||||
|
||||
core.trustctime::
|
||||
If false, the ctime differences between the index and the
|
||||
working copy are ignored; useful when the inode change time
|
||||
@@ -224,7 +244,11 @@ core.symlinks::
|
||||
contain the link text. linkgit:git-update-index[1] and
|
||||
linkgit:git-add[1] will not change the recorded type to regular
|
||||
file. Useful on filesystems like FAT that do not support
|
||||
symbolic links. True by default.
|
||||
symbolic links.
|
||||
+
|
||||
The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
|
||||
will probe and set core.symlinks false if appropriate when the repository
|
||||
is created.
|
||||
|
||||
core.gitProxy::
|
||||
A "proxy command" to execute (as 'command host port') instead
|
||||
@@ -611,10 +635,10 @@ color.diff.<slot>::
|
||||
Use customized color for diff colorization. `<slot>` specifies
|
||||
which part of the patch to use the specified color, and is one
|
||||
of `plain` (context text), `meta` (metainformation), `frag`
|
||||
(hunk header), `old` (removed lines), `new` (added lines),
|
||||
`commit` (commit headers), or `whitespace` (highlighting
|
||||
whitespace errors). The values of these variables may be specified as
|
||||
in color.branch.<slot>.
|
||||
(hunk header), 'func' (function in hunk header), `old` (removed lines),
|
||||
`new` (added lines), `commit` (commit headers), or `whitespace`
|
||||
(highlighting whitespace errors). The values of these variables may be
|
||||
specified as in color.branch.<slot>.
|
||||
|
||||
color.grep::
|
||||
When set to `always`, always highlight matches. When `false` (or
|
||||
@@ -1417,7 +1441,13 @@ remote.<name>.mirror::
|
||||
|
||||
remote.<name>.skipDefaultUpdate::
|
||||
If true, this remote will be skipped by default when updating
|
||||
using the update subcommand of linkgit:git-remote[1].
|
||||
using linkgit:git-fetch[1] or the `update` subcommand of
|
||||
linkgit:git-remote[1].
|
||||
|
||||
remote.<name>.skipFetchAll::
|
||||
If true, this remote will be skipped by default when updating
|
||||
using linkgit:git-fetch[1] or the `update` subcommand of
|
||||
linkgit:git-remote[1].
|
||||
|
||||
remote.<name>.receivepack::
|
||||
The default program to execute on the remote side when pushing. See
|
||||
|
||||
@@ -85,10 +85,23 @@ ifndef::git-format-patch[]
|
||||
endif::git-format-patch[]
|
||||
|
||||
ifndef::git-format-patch[]
|
||||
|
||||
-z::
|
||||
NUL-line termination on output. This affects the `--raw`
|
||||
output field terminator. Also output from commands such
|
||||
as `git-log` will be delimited with NUL between commits.
|
||||
ifdef::git-log[]
|
||||
Separate the commits with NULs instead of with new newlines.
|
||||
+
|
||||
Also, when `--raw` or `--numstat` has been given, do not munge
|
||||
pathnames and use NULs as output field terminators.
|
||||
endif::git-log[]
|
||||
ifndef::git-log[]
|
||||
When `--raw` or `--numstat` has been given, do not munge
|
||||
pathnames and use NULs as output field terminators.
|
||||
endif::git-log[]
|
||||
+
|
||||
Without this option, each pathname output will have TAB, LF, double quotes,
|
||||
and backslash characters replaced with `\t`, `\n`, `\"`, and `\\`,
|
||||
respectively, and the pathname will be enclosed in double quotes if
|
||||
any of those replacements occurred.
|
||||
|
||||
--name-only::
|
||||
Show only names of changed files.
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
--all::
|
||||
Fetch all remotes.
|
||||
|
||||
-a::
|
||||
--append::
|
||||
Append ref names and object names of fetched refs to the
|
||||
@@ -9,6 +12,11 @@
|
||||
`git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
|
||||
by the specified number of commits.
|
||||
|
||||
ifndef::git-pull[]
|
||||
--dry-run::
|
||||
Show what would be done, without making any changes.
|
||||
endif::git-pull[]
|
||||
|
||||
-f::
|
||||
--force::
|
||||
When 'git-fetch' is used with `<rbranch>:<lbranch>`
|
||||
@@ -21,6 +29,16 @@
|
||||
--keep::
|
||||
Keep downloaded pack.
|
||||
|
||||
ifndef::git-pull[]
|
||||
--multiple::
|
||||
Allow several <repository> and <group> arguments to be
|
||||
specified. No <refspec>s may be specified.
|
||||
|
||||
--prune::
|
||||
After fetching, remove any remote tracking branches which
|
||||
no longer exist on the remote.
|
||||
endif::git-pull[]
|
||||
|
||||
ifdef::git-pull[]
|
||||
--no-tags::
|
||||
endif::git-pull[]
|
||||
|
||||
@@ -3,7 +3,7 @@ git-apply(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-apply - Apply a patch on a git index file and/or a working tree
|
||||
git-apply - Apply a patch to files and/or to the index
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
@@ -20,8 +20,11 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Reads supplied 'diff' output and applies it on a git index file
|
||||
and a work tree.
|
||||
Reads the supplied diff output (i.e. "a patch") and applies it to files.
|
||||
With the `--index` option the patch is also applied to the index, and
|
||||
with the `--cache` option the patch is only applied to the index.
|
||||
Without these options, the command applies the patch only to files,
|
||||
and does not require them to be in a git repository.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@@ -34,7 +37,7 @@ OPTIONS
|
||||
input. Turns off "apply".
|
||||
|
||||
--numstat::
|
||||
Similar to \--stat, but shows the number of added and
|
||||
Similar to `--stat`, but shows the number of added and
|
||||
deleted lines in decimal notation and the pathname without
|
||||
abbreviation, to make it more machine friendly. For
|
||||
binary files, outputs two `-` instead of saying
|
||||
@@ -48,22 +51,22 @@ OPTIONS
|
||||
|
||||
--check::
|
||||
Instead of applying the patch, see if the patch is
|
||||
applicable to the current work tree and/or the index
|
||||
applicable to the current working tree and/or the index
|
||||
file and detects errors. Turns off "apply".
|
||||
|
||||
--index::
|
||||
When --check is in effect, or when applying the patch
|
||||
When `--check` is in effect, or when applying the patch
|
||||
(which is the default when none of the options that
|
||||
disables it is in effect), make sure the patch is
|
||||
applicable to what the current index file records. If
|
||||
the file to be patched in the work tree is not
|
||||
the file to be patched in the working tree is not
|
||||
up-to-date, it is flagged as an error. This flag also
|
||||
causes the index file to be updated.
|
||||
|
||||
--cached::
|
||||
Apply a patch without touching the working tree. Instead take the
|
||||
cached data, apply the patch, and store the result in the index
|
||||
without using the working tree. This implies '--index'.
|
||||
without using the working tree. This implies `--index`.
|
||||
|
||||
--build-fake-ancestor=<file>::
|
||||
Newer 'git-diff' output has embedded 'index information'
|
||||
@@ -87,11 +90,13 @@ the information is read from the current index instead.
|
||||
rejected hunks in corresponding *.rej files.
|
||||
|
||||
-z::
|
||||
When showing the index information, do not munge paths,
|
||||
but use NUL terminated machine readable format. Without
|
||||
this flag, the pathnames output will have TAB, LF, and
|
||||
backslash characters replaced with `\t`, `\n`, and `\\`,
|
||||
respectively.
|
||||
When `--numstat` has been given, do not munge pathnames,
|
||||
but use a NUL-terminated machine-readable format.
|
||||
+
|
||||
Without this option, each pathname output will have TAB, LF, double quotes,
|
||||
and backslash characters replaced with `\t`, `\n`, `\"`, and `\\`,
|
||||
respectively, and the pathname will be enclosed in double quotes if
|
||||
any of those replacements occurred.
|
||||
|
||||
-p<n>::
|
||||
Remove <n> leading slashes from traditional diff paths. The
|
||||
@@ -107,8 +112,8 @@ the information is read from the current index instead.
|
||||
By default, 'git-apply' expects that the patch being
|
||||
applied is a unified diff with at least one line of context.
|
||||
This provides good safety measures, but breaks down when
|
||||
applying a diff generated with --unified=0. To bypass these
|
||||
checks use '--unidiff-zero'.
|
||||
applying a diff generated with `--unified=0`. To bypass these
|
||||
checks use `--unidiff-zero`.
|
||||
+
|
||||
Note, for the reasons stated above usage of context-free patches is
|
||||
discouraged.
|
||||
@@ -144,7 +149,7 @@ discouraged.
|
||||
be useful when importing patchsets, where you want to include certain
|
||||
files or directories.
|
||||
+
|
||||
When --exclude and --include patterns are used, they are examined in the
|
||||
When `--exclude` and `--include` patterns are used, they are examined in the
|
||||
order they appear on the command line, and the first match determines if a
|
||||
patch to each path is used. A patch to a path that does not match any
|
||||
include/exclude pattern is used by default if there is no include pattern
|
||||
@@ -227,13 +232,13 @@ Submodules
|
||||
If the patch contains any changes to submodules then 'git-apply'
|
||||
treats these changes as follows.
|
||||
|
||||
If --index is specified (explicitly or implicitly), then the submodule
|
||||
If `--index` is specified (explicitly or implicitly), then the submodule
|
||||
commits must match the index exactly for the patch to apply. If any
|
||||
of the submodules are checked-out, then these check-outs are completely
|
||||
ignored, i.e., they are not required to be up-to-date or clean and they
|
||||
are not updated.
|
||||
|
||||
If --index is not specified, then the submodule commits in the patch
|
||||
If `--index` is not specified, then the submodule commits in the patch
|
||||
are ignored and only the absence or presence of the corresponding
|
||||
subdirectory is checked and (if possible) updated.
|
||||
|
||||
|
||||
1358
Documentation/git-bisect-lk2009.txt
Normal file
1358
Documentation/git-bisect-lk2009.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -330,6 +330,11 @@ Documentation
|
||||
-------------
|
||||
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
link:git-bisect-lk2009.html[Fighting regressions with git bisect],
|
||||
linkgit:git-blame[1].
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[1] suite
|
||||
|
||||
@@ -24,7 +24,7 @@ ssh, rsync, http) cannot be used. This command provides support for
|
||||
'git-fetch' and 'git-pull' to operate by packaging objects and references
|
||||
in an archive at the originating machine, then importing those into
|
||||
another repository using 'git-fetch' and 'git-pull'
|
||||
after moving the archive by some means (i.e., by sneakernet). As no
|
||||
after moving the archive by some means (e.g., by sneakernet). As no
|
||||
direct connection between the repositories exists, the user must specify a
|
||||
basis for the bundle that is held by the destination repository: the
|
||||
bundle assumes that all objects in the basis are already in the
|
||||
|
||||
@@ -11,7 +11,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git clone' [--template=<template_directory>]
|
||||
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
|
||||
[-o <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[--depth <depth>] [--recursive] [--] <repository> [<directory>]
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]
|
||||
[(-c | -C) <commit>] [-F <file> | -m <msg>]
|
||||
[(-c | -C) <commit>] [-F <file> | -m <msg>] [--reset-author]
|
||||
[--allow-empty] [--no-verify] [-e] [--author=<author>]
|
||||
[--cleanup=<mode>] [--] [[-i | -o ]<file>...]
|
||||
|
||||
@@ -69,6 +69,11 @@ OPTIONS
|
||||
Like '-C', but with '-c' the editor is invoked, so that
|
||||
the user can further edit the commit message.
|
||||
|
||||
--reset-author::
|
||||
When used with -C/-c/--amend options, declare that the
|
||||
authorship of the resulting commit now belongs of the committer.
|
||||
This also renews the author timestamp.
|
||||
|
||||
-F <file>::
|
||||
--file=<file>::
|
||||
Take the commit message from the given file. Use '-' to
|
||||
|
||||
@@ -182,10 +182,9 @@ Database Backend
|
||||
----------------
|
||||
|
||||
'git-cvsserver' uses one database per git head (i.e. CVS module) to
|
||||
store information about the repository for faster access. The
|
||||
database doesn't contain any persistent data and can be completely
|
||||
regenerated from the git repository at any time. The database
|
||||
needs to be updated (i.e. written to) after every commit.
|
||||
store information about the repository to maintain consistent
|
||||
CVS revision numbers. The database needs to be
|
||||
updated (i.e. written to) after every commit.
|
||||
|
||||
If the commit is done directly by using `git` (as opposed to
|
||||
using 'git-cvsserver') the update will need to happen on the
|
||||
@@ -204,6 +203,18 @@ write so it might not be enough to grant the users using
|
||||
'git-cvsserver' write access to the database file without granting
|
||||
them write access to the directory, too.
|
||||
|
||||
The database can not be reliably regenerated in a
|
||||
consistent form after the branch it is tracking has changed.
|
||||
Example: For merged branches, 'git-cvsserver' only tracks
|
||||
one branch of development, and after a 'git-merge' an
|
||||
incrementally updated database may track a different branch
|
||||
than a database regenerated from scratch, causing inconsistent
|
||||
CVS revision numbers. `git-cvsserver` has no way of knowing which
|
||||
branch it would have picked if it had been run incrementally
|
||||
pre-merge. So if you have to fully or partially (from old
|
||||
backup) regenerate the database, you should be suspicious
|
||||
of pre-existing CVS sandboxes.
|
||||
|
||||
You can configure the database backend with the following
|
||||
configuration variables:
|
||||
|
||||
|
||||
@@ -10,11 +10,17 @@ SYNOPSIS
|
||||
--------
|
||||
'git fetch' <options> <repository> <refspec>...
|
||||
|
||||
'git fetch' <options> <group>
|
||||
|
||||
'git fetch' --multiple <options> [<repository> | <group>]...
|
||||
|
||||
'git fetch' --all <options>
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Fetches named heads or tags from another repository, along with
|
||||
the objects necessary to complete them.
|
||||
Fetches named heads or tags from one or more other repositories,
|
||||
along with the objects necessary to complete them.
|
||||
|
||||
The ref names and their object names of fetched refs are stored
|
||||
in `.git/FETCH_HEAD`. This information is left for a later merge
|
||||
@@ -28,6 +34,10 @@ pointed by remote tags that it does not yet have, then fetch
|
||||
those missing tags. If the other end has tags that point at
|
||||
branches you are not interested in, you will not get them.
|
||||
|
||||
'git fetch' can fetch from either a single named repository, or
|
||||
or from several repositories at once if <group> is given and
|
||||
there is a remotes.<group> entry in the configuration file.
|
||||
(See linkgit:git-config[1]).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
@@ -8,7 +8,7 @@ git-mailinfo - Extracts patch and authorship from a single e-mail message
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git mailinfo' [-k] [-u | --encoding=<encoding> | -n] [--scissors] <msg> <patch>
|
||||
'git mailinfo' [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors] <msg> <patch>
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@@ -32,6 +32,11 @@ OPTIONS
|
||||
munging, and is most useful when used to read back
|
||||
'git-format-patch -k' output.
|
||||
|
||||
-b::
|
||||
When -k is not in effect, all leading strings bracketed with '['
|
||||
and ']' pairs are stripped. This option limits the stripping to
|
||||
only the pairs whose bracketed string contains the word "PATCH".
|
||||
|
||||
-u::
|
||||
The commit log message, author name and author email are
|
||||
taken from the e-mail, and after minimally decoding MIME
|
||||
|
||||
@@ -9,8 +9,9 @@ git-pack-objects - Create a packed archive of objects
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git pack-objects' [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty]
|
||||
[--local] [--incremental] [--window=N] [--depth=N] [--all-progress]
|
||||
'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied]
|
||||
[--no-reuse-delta] [--delta-base-offset] [--non-empty]
|
||||
[--local] [--incremental] [--window=N] [--depth=N]
|
||||
[--revs [--unpacked | --all]*] [--stdout | base-name]
|
||||
[--keep-true-parents] < object-list
|
||||
|
||||
@@ -137,7 +138,7 @@ base-name::
|
||||
|
||||
--all-progress::
|
||||
When --stdout is specified then progress report is
|
||||
displayed during the object count and deltification phases
|
||||
displayed during the object count and compression phases
|
||||
but inhibited during the write-out phase. The reason is
|
||||
that in some cases the output stream is directly linked
|
||||
to another command which may wish to display progress
|
||||
@@ -146,6 +147,11 @@ base-name::
|
||||
report for the write-out phase as well even if --stdout is
|
||||
used.
|
||||
|
||||
--all-progress-implied::
|
||||
This is used to imply --all-progress whenever progress display
|
||||
is activated. Unlike --all-progress this flag doesn't actually
|
||||
force any progress display by itself.
|
||||
|
||||
-q::
|
||||
This flag makes the command not to report its progress
|
||||
on the standard error stream.
|
||||
|
||||
@@ -17,31 +17,35 @@ DESCRIPTION
|
||||
Adds a 'replace' reference in `.git/refs/replace/`
|
||||
|
||||
The name of the 'replace' reference is the SHA1 of the object that is
|
||||
replaced. The content of the replace reference is the SHA1 of the
|
||||
replaced. The content of the 'replace' reference is the SHA1 of the
|
||||
replacement object.
|
||||
|
||||
Unless `-f` is given, the replace reference must not yet exist in
|
||||
Unless `-f` is given, the 'replace' reference must not yet exist in
|
||||
`.git/refs/replace/` directory.
|
||||
|
||||
Replace references will be used by default by all git commands except
|
||||
those doing reachability traversal (prune, pack transfer and fsck).
|
||||
Replacement references will be used by default by all git commands
|
||||
except those doing reachability traversal (prune, pack transfer and
|
||||
fsck).
|
||||
|
||||
It is possible to disable use of replacement refs for any command
|
||||
using the --no-replace-objects option just after "git".
|
||||
It is possible to disable use of replacement references for any
|
||||
command using the `--no-replace-objects` option just after 'git'.
|
||||
|
||||
For example if commit "foo" has been replaced by commit "bar":
|
||||
For example if commit 'foo' has been replaced by commit 'bar':
|
||||
|
||||
------------------------------------------------
|
||||
$ git --no-replace-object cat-file commit foo
|
||||
$ git --no-replace-objects cat-file commit foo
|
||||
------------------------------------------------
|
||||
|
||||
show information about commit "foo", while:
|
||||
shows information about commit 'foo', while:
|
||||
|
||||
------------------------------------------------
|
||||
$ git cat-file commit foo
|
||||
------------------------------------------------
|
||||
|
||||
show information about commit "bar".
|
||||
shows information about commit 'bar'.
|
||||
|
||||
The 'GIT_NO_REPLACE_OBJECTS' environment variable can be set to
|
||||
achieve the same effect as the `--no-replace-objects` option.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
@@ -108,9 +108,10 @@ Sending
|
||||
--envelope-sender=<address>::
|
||||
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. Default is the value of
|
||||
the 'sendemail.envelopesender' configuration variable; if that is
|
||||
subscribed to a list. In order to use the 'From' address, set the
|
||||
value to "auto". If you use the sendmail binary, you must have
|
||||
suitable privileges for the -f parameter. Default is the value of the
|
||||
'sendemail.envelopesender' configuration variable; if that is
|
||||
unspecified, choosing the envelope sender is left to your MTA.
|
||||
|
||||
--smtp-encryption=<encryption>::
|
||||
|
||||
@@ -602,7 +602,7 @@ $ git tag -s <tagname>
|
||||
----------------
|
||||
|
||||
which will sign the current `HEAD` (but you can also give it another
|
||||
argument that specifies the thing to tag, i.e., you could have tagged the
|
||||
argument that specifies the thing to tag, e.g., you could have tagged the
|
||||
current `mybranch` point by using `git tag <tagname> mybranch`).
|
||||
|
||||
You normally only do signed tags for major releases or things
|
||||
@@ -1186,9 +1186,9 @@ $ git show-branch
|
||||
* [master] Some fun.
|
||||
! [mybranch] Some work.
|
||||
--
|
||||
+ [mybranch] Some work.
|
||||
* [master] Some fun.
|
||||
*+ [mybranch^] Initial commit
|
||||
+ [mybranch] Some work.
|
||||
*+ [master^] Initial commit
|
||||
------------
|
||||
|
||||
Now we are ready to experiment with the merge by hand.
|
||||
|
||||
@@ -229,7 +229,7 @@ To verify that 'master' is indeed a superset of 'maint', use git log:
|
||||
.Verify 'master' is a superset of 'maint'
|
||||
[caption="Recipe: "]
|
||||
=====================================
|
||||
git log master..maint
|
||||
`git log master..maint`
|
||||
=====================================
|
||||
|
||||
This command should not list any commits. Otherwise, check out
|
||||
|
||||
@@ -136,9 +136,7 @@ The placeholders are:
|
||||
- '%n': newline
|
||||
- '%x00': print a byte from a hex code
|
||||
- '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
|
||||
linkgit:git-shortlog[1]. NOTE: Color placeholders (`%C*`) are not
|
||||
recognized as having no width, so they should not be put into wrapped
|
||||
sections.
|
||||
linkgit:git-shortlog[1].
|
||||
|
||||
NOTE: Some placeholders may depend on other options given to the
|
||||
revision traversal engine. For example, the `%g*` reflog options will
|
||||
@@ -146,6 +144,14 @@ insert an empty string unless we are traversing reflog entries (e.g., by
|
||||
`git log -g`). The `%d` placeholder will use the "short" decoration
|
||||
format if `--decorate` was not already provided on the command line.
|
||||
|
||||
If you add a `{plus}` (plus sign) after '%' of a placeholder, a line-feed
|
||||
is inserted immediately before the expansion if and only if the
|
||||
placeholder expands to a non-empty string.
|
||||
|
||||
If you add a `-` (minus sign) after '%' of a placeholder, line-feeds that
|
||||
immediately precede the expansion are deleted if and only if the
|
||||
placeholder expands to an empty string.
|
||||
|
||||
* 'tformat:'
|
||||
+
|
||||
The 'tformat:' format works exactly like 'format:', except that it
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
(see the section <<URLS,GIT URLS>> below) or the name
|
||||
of a remote (see the section <<REMOTES,REMOTES>> below).
|
||||
|
||||
ifndef::git-pull[]
|
||||
<group>::
|
||||
A name referring to a list of repositories as the value
|
||||
of remotes.<group> in the configuration file.
|
||||
(See linkgit:git-config[1]).
|
||||
endif::git-pull[]
|
||||
|
||||
<refspec>::
|
||||
The format of a <refspec> parameter is an optional plus
|
||||
`{plus}`, followed by the source ref <src>, followed
|
||||
|
||||
@@ -243,12 +243,23 @@ endif::git-rev-list[]
|
||||
Pretend as if all the refs in `$GIT_DIR/refs/remotes` are listed
|
||||
on the command line as '<commit>'.
|
||||
|
||||
ifdef::git-rev-list[]
|
||||
ifndef::git-rev-list[]
|
||||
--bisect::
|
||||
|
||||
Pretend as if the bad bisection ref `$GIT_DIR/refs/bisect/bad`
|
||||
was listed and as if it was followed by `--not` and the good
|
||||
bisection refs `$GIT_DIR/refs/bisect/good-*` on the command
|
||||
line.
|
||||
endif::git-rev-list[]
|
||||
|
||||
--stdin::
|
||||
|
||||
In addition to the '<commit>' listed on the command
|
||||
line, read them from the standard input.
|
||||
line, read them from the standard input. If a '--' separator is
|
||||
seen, stop reading commits and start reading paths to limit the
|
||||
result.
|
||||
|
||||
ifdef::git-rev-list[]
|
||||
--quiet::
|
||||
|
||||
Don't print anything to standard output. This form
|
||||
@@ -536,7 +547,11 @@ Bisection Helpers
|
||||
--bisect::
|
||||
|
||||
Limit output to the one commit object which is roughly halfway between
|
||||
the included and excluded commits. Thus, if
|
||||
included and excluded commits. Note that the bad bisection ref
|
||||
`$GIT_DIR/refs/bisect/bad` is added to the included commits (if it
|
||||
exists) and the good bisection refs `$GIT_DIR/refs/bisect/good-*` are
|
||||
added to the excluded commits (if they exist). Thus, supposing there
|
||||
are no refs in `$GIT_DIR/refs/bisect/`, if
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$ git rev-list --bisect foo ^bar ^baz
|
||||
@@ -556,22 +571,24 @@ one.
|
||||
|
||||
--bisect-vars::
|
||||
|
||||
This calculates the same as `--bisect`, but outputs text ready
|
||||
to be eval'ed by the shell. These lines will assign the name of
|
||||
the midpoint revision to the variable `bisect_rev`, and the
|
||||
expected number of commits to be tested after `bisect_rev` is
|
||||
tested to `bisect_nr`, the expected number of commits to be
|
||||
tested if `bisect_rev` turns out to be good to `bisect_good`,
|
||||
the expected number of commits to be tested if `bisect_rev`
|
||||
turns out to be bad to `bisect_bad`, and the number of commits
|
||||
we are bisecting right now to `bisect_all`.
|
||||
This calculates the same as `--bisect`, except that refs in
|
||||
`$GIT_DIR/refs/bisect/` are not used, and except that this outputs
|
||||
text ready to be eval'ed by the shell. These lines will assign the
|
||||
name of the midpoint revision to the variable `bisect_rev`, and the
|
||||
expected number of commits to be tested after `bisect_rev` is tested
|
||||
to `bisect_nr`, the expected number of commits to be tested if
|
||||
`bisect_rev` turns out to be good to `bisect_good`, the expected
|
||||
number of commits to be tested if `bisect_rev` turns out to be bad to
|
||||
`bisect_bad`, and the number of commits we are bisecting right now to
|
||||
`bisect_all`.
|
||||
|
||||
--bisect-all::
|
||||
|
||||
This outputs all the commit objects between the included and excluded
|
||||
commits, ordered by their distance to the included and excluded
|
||||
commits. The farthest from them is displayed first. (This is the only
|
||||
one displayed by `--bisect`.)
|
||||
commits. Refs in `$GIT_DIR/refs/bisect/` are not used. The farthest
|
||||
from them is displayed first. (This is the only one displayed by
|
||||
`--bisect`.)
|
||||
+
|
||||
This is useful because it makes it easy to choose a good commit to
|
||||
test when you want to avoid to test some of them for some reason (they
|
||||
|
||||
@@ -1183,7 +1183,23 @@ $ git merge branchname
|
||||
-------------------------------------------------
|
||||
|
||||
merges the development in the branch "branchname" into the current
|
||||
branch. If there are conflicts--for example, if the same file is
|
||||
branch.
|
||||
|
||||
A merge is made by combining the changes made in "branchname" and the
|
||||
changes made up to the latest commit in your current branch since
|
||||
their histories forked. The work tree is overwritten by the result of
|
||||
the merge when this combining is done cleanly, or overwritten by a
|
||||
half-merged results when this combining results in conflicts.
|
||||
Therefore, if you have uncommitted changes touching the same files as
|
||||
the ones impacted by the merge, Git will refuse to proceed. Most of
|
||||
the time, you will want to commit your changes before you can merge,
|
||||
and if you don't, then linkgit:git-stash[1] can take these changes
|
||||
away while you're doing the merge, and reapply them afterwards.
|
||||
|
||||
If the changes are independant enough, Git will automatically complete
|
||||
the merge and commit the result (or reuse an existing commit in case
|
||||
of <<fast-forwards,fast-forward>>, see below). On the other hand,
|
||||
if there are conflicts--for example, if the same file is
|
||||
modified in two different ways in the remote branch and the local
|
||||
branch--then you are warned; the output may look something like this:
|
||||
|
||||
@@ -1679,7 +1695,7 @@ Sharing development with others
|
||||
Getting updates with git pull
|
||||
-----------------------------
|
||||
|
||||
After you clone a repository and make a few changes of your own, you
|
||||
After you clone a repository and commit a few changes of your own, you
|
||||
may wish to check the original repository for updates and merge them
|
||||
into your own work.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.6.5.GIT
|
||||
DEF_VER=v1.6.6-rc1.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
30
Makefile
30
Makefile
@@ -205,6 +205,9 @@ all::
|
||||
#
|
||||
# Define NO_REGEX if you have no or inferior regex support in your C library.
|
||||
#
|
||||
# Define JSMIN to point to JavaScript minifier that functions as
|
||||
# a filter to have gitweb.js minified.
|
||||
#
|
||||
# Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
|
||||
# you want to use something different. The value will be interpreted by the
|
||||
# shell at runtime when it is used.
|
||||
@@ -274,6 +277,9 @@ lib = lib
|
||||
# DESTDIR=
|
||||
pathsep = :
|
||||
|
||||
# JavaScript minifier invocation that can function as filter
|
||||
JSMIN =
|
||||
|
||||
# default configuration for gitweb
|
||||
GITWEB_CONFIG = gitweb_config.perl
|
||||
GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
|
||||
@@ -289,6 +295,11 @@ GITWEB_HOMETEXT = indextext.html
|
||||
GITWEB_CSS = gitweb.css
|
||||
GITWEB_LOGO = git-logo.png
|
||||
GITWEB_FAVICON = git-favicon.png
|
||||
ifdef JSMIN
|
||||
GITWEB_JS = gitweb.min.js
|
||||
else
|
||||
GITWEB_JS = gitweb.js
|
||||
endif
|
||||
GITWEB_SITE_HEADER =
|
||||
GITWEB_SITE_FOOTER =
|
||||
|
||||
@@ -805,6 +816,7 @@ ifeq ($(uname_O),Cygwin)
|
||||
NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
|
||||
NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
|
||||
OLD_ICONV = UnfortunatelyYes
|
||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||
# There are conflicting reports about this.
|
||||
# On some boxes NO_MMAP is needed, and not so elsewhere.
|
||||
# Try commenting this out if you suspect MMAP is more efficient
|
||||
@@ -982,7 +994,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
NEEDS_CRYPTO_WITH_SSL = YesPlease
|
||||
NO_LIBGEN_H = YesPlease
|
||||
NO_SYMLINK_HEAD = YesPlease
|
||||
NO_IPV6 = YesPlease
|
||||
NO_SETENV = YesPlease
|
||||
NO_UNSETENV = YesPlease
|
||||
NO_STRCASESTR = YesPlease
|
||||
@@ -1498,8 +1509,13 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||
chmod +x $@+ && \
|
||||
mv $@+ $@
|
||||
|
||||
ifdef JSMIN
|
||||
OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.min.js
|
||||
gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
|
||||
else
|
||||
OTHER_PROGRAMS += gitweb/gitweb.cgi
|
||||
gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||
endif
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
||||
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
|
||||
@@ -1518,13 +1534,14 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||
-e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
|
||||
-e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
|
||||
-e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
|
||||
-e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
|
||||
-e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
|
||||
-e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
|
||||
$< >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
mv $@+ $@
|
||||
|
||||
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
@@ -1533,6 +1550,8 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||
-e '/@@GITWEB_CGI@@/d' \
|
||||
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
|
||||
-e '/@@GITWEB_CSS@@/d' \
|
||||
-e '/@@GITWEB_JS@@/r gitweb/gitweb.js' \
|
||||
-e '/@@GITWEB_JS@@/d' \
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
$@.sh > $@+ && \
|
||||
chmod +x $@+ && \
|
||||
@@ -1547,6 +1566,11 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
|
||||
mv $@+ $@
|
||||
endif # NO_PERL
|
||||
|
||||
ifdef JSMIN
|
||||
gitweb/gitweb.min.js: gitweb/gitweb.js
|
||||
$(QUIET_GEN)$(JSMIN) <$< >$@
|
||||
endif # JSMIN
|
||||
|
||||
configure: configure.ac
|
||||
$(QUIET_GEN)$(RM) $@ $<+ && \
|
||||
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
@@ -1874,7 +1898,7 @@ distclean: clean
|
||||
$(RM) configure
|
||||
|
||||
clean:
|
||||
$(RM) *.o block-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
|
||||
$(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
|
||||
$(LIB_FILE) $(XDIFF_LIB)
|
||||
$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||
$(RM) $(TEST_PROGRAMS)
|
||||
|
||||
2
advice.c
2
advice.c
@@ -2,6 +2,7 @@
|
||||
|
||||
int advice_push_nonfastforward = 1;
|
||||
int advice_status_hints = 1;
|
||||
int advice_commit_before_merge = 1;
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
@@ -9,6 +10,7 @@ static struct {
|
||||
} advice_config[] = {
|
||||
{ "pushnonfastforward", &advice_push_nonfastforward },
|
||||
{ "statushints", &advice_status_hints },
|
||||
{ "commitbeforemerge", &advice_commit_before_merge },
|
||||
};
|
||||
|
||||
int git_default_advice_config(const char *var, const char *value)
|
||||
|
||||
1
advice.h
1
advice.h
@@ -3,6 +3,7 @@
|
||||
|
||||
extern int advice_push_nonfastforward;
|
||||
extern int advice_status_hints;
|
||||
extern int advice_commit_before_merge;
|
||||
|
||||
int git_default_advice_config(const char *var, const char *value);
|
||||
|
||||
|
||||
@@ -823,12 +823,13 @@ static int gitdiff_unrecognized(const char *line, struct patch *patch)
|
||||
|
||||
static const char *stop_at_slash(const char *line, int llen)
|
||||
{
|
||||
int nslash = p_value;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < llen; i++) {
|
||||
int ch = line[i];
|
||||
if (ch == '/')
|
||||
return line + i;
|
||||
if (ch == '/' && --nslash <= 0)
|
||||
return &line[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2358,6 +2358,7 @@ parse_done:
|
||||
die_errno("cannot stat path '%s'", path);
|
||||
}
|
||||
|
||||
revs.disable_stdin = 1;
|
||||
setup_revisions(argc, argv, &revs, NULL);
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ static const char *template_file;
|
||||
static char *edit_message, *use_message;
|
||||
static char *author_name, *author_email, *author_date;
|
||||
static int all, edit_flag, also, interactive, only, amend, signoff;
|
||||
static int quiet, verbose, no_verify, allow_empty, dry_run;
|
||||
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
||||
static char *untracked_files_arg;
|
||||
/*
|
||||
* The default commit message cleanup mode will remove the lines
|
||||
@@ -91,8 +91,9 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_FILENAME('F', "file", &logfile, "read log from file"),
|
||||
OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
|
||||
OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
|
||||
OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
|
||||
OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"),
|
||||
OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
|
||||
OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
|
||||
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
|
||||
OPT_FILENAME('t', "template", &template_file, "use specified template file"),
|
||||
OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
|
||||
@@ -381,7 +382,7 @@ static void determine_author_info(void)
|
||||
email = getenv("GIT_AUTHOR_EMAIL");
|
||||
date = getenv("GIT_AUTHOR_DATE");
|
||||
|
||||
if (use_message) {
|
||||
if (use_message && !renew_authorship) {
|
||||
const char *a, *lb, *rb, *eol;
|
||||
|
||||
a = strstr(use_message_buffer, "\nauthor ");
|
||||
@@ -747,6 +748,9 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
if (force_author && !strchr(force_author, '>'))
|
||||
force_author = find_author_by_nickname(force_author);
|
||||
|
||||
if (force_author && renew_authorship)
|
||||
die("Using both --reset-author and --author does not make sense");
|
||||
|
||||
if (logfile || message.len || use_message)
|
||||
use_editor = 0;
|
||||
if (edit_flag)
|
||||
@@ -780,6 +784,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
use_message = edit_message;
|
||||
if (amend && !use_message)
|
||||
use_message = "HEAD";
|
||||
if (!use_message && renew_authorship)
|
||||
die("--reset-author can be used only with -C, -c or --amend.");
|
||||
if (use_message) {
|
||||
unsigned char sha1[20];
|
||||
static char utf8[] = "UTF-8";
|
||||
|
||||
@@ -104,6 +104,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
|
||||
opt->abbrev = 0;
|
||||
opt->diff = 1;
|
||||
opt->disable_stdin = 1;
|
||||
argc = setup_revisions(argc, argv, opt, NULL);
|
||||
|
||||
while (--argc > 0) {
|
||||
|
||||
198
builtin-fetch.c
198
builtin-fetch.c
@@ -14,6 +14,9 @@
|
||||
|
||||
static const char * const builtin_fetch_usage[] = {
|
||||
"git fetch [options] [<repository> <refspec>...]",
|
||||
"git fetch [options] <group>",
|
||||
"git fetch --multiple [options] [<repository> | <group>]...",
|
||||
"git fetch --all [options]",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -23,7 +26,7 @@ enum {
|
||||
TAGS_SET = 2
|
||||
};
|
||||
|
||||
static int append, force, keep, update_head_ok, verbosity;
|
||||
static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
|
||||
static int tags = TAGS_DEFAULT;
|
||||
static const char *depth;
|
||||
static const char *upload_pack;
|
||||
@@ -32,16 +35,24 @@ static struct transport *transport;
|
||||
|
||||
static struct option builtin_fetch_options[] = {
|
||||
OPT__VERBOSITY(&verbosity),
|
||||
OPT_BOOLEAN(0, "all", &all,
|
||||
"fetch from all remotes"),
|
||||
OPT_BOOLEAN('a', "append", &append,
|
||||
"append to .git/FETCH_HEAD instead of overwriting"),
|
||||
OPT_STRING(0, "upload-pack", &upload_pack, "PATH",
|
||||
"path to upload pack on remote end"),
|
||||
OPT_BOOLEAN('f', "force", &force,
|
||||
"force overwrite of local branch"),
|
||||
OPT_BOOLEAN('m', "multiple", &multiple,
|
||||
"fetch from multiple remotes"),
|
||||
OPT_SET_INT('t', "tags", &tags,
|
||||
"fetch all tags and associated objects", TAGS_SET),
|
||||
OPT_SET_INT('n', NULL, &tags,
|
||||
"do not fetch all tags (--no-tags)", TAGS_UNSET),
|
||||
OPT_BOOLEAN('p', "prune", &prune,
|
||||
"prune tracking branches no longer on remote"),
|
||||
OPT_BOOLEAN(0, "dry-run", &dry_run,
|
||||
"dry run"),
|
||||
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
|
||||
OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
|
||||
"allow updating of HEAD ref"),
|
||||
@@ -178,6 +189,8 @@ static int s_update_ref(const char *action,
|
||||
char *rla = getenv("GIT_REFLOG_ACTION");
|
||||
static struct ref_lock *lock;
|
||||
|
||||
if (dry_run)
|
||||
return 0;
|
||||
if (!rla)
|
||||
rla = default_rla.buf;
|
||||
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
|
||||
@@ -303,7 +316,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
char note[1024];
|
||||
const char *what, *kind;
|
||||
struct ref *rm;
|
||||
char *url, *filename = git_path("FETCH_HEAD");
|
||||
char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
|
||||
|
||||
fp = fopen(filename, "a");
|
||||
if (!fp)
|
||||
@@ -485,6 +498,28 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int prune_refs(struct transport *transport, struct ref *ref_map)
|
||||
{
|
||||
int result = 0;
|
||||
struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
|
||||
const char *dangling_msg = dry_run
|
||||
? " (%s will become dangling)\n"
|
||||
: " (%s has become dangling)\n";
|
||||
|
||||
for (ref = stale_refs; ref; ref = ref->next) {
|
||||
if (!dry_run)
|
||||
result |= delete_ref(ref->name, NULL, 0);
|
||||
if (verbosity >= 0) {
|
||||
fprintf(stderr, " x %-*s %-*s -> %s\n",
|
||||
SUMMARY_WIDTH, "[deleted]",
|
||||
REFCOL_WIDTH, "(none)", prettify_refname(ref->name));
|
||||
warn_dangling_symref(stderr, dangling_msg, ref->name);
|
||||
}
|
||||
}
|
||||
free_refs(stale_refs);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int add_existing(const char *refname, const unsigned char *sha1,
|
||||
int flag, void *cbdata)
|
||||
{
|
||||
@@ -633,7 +668,7 @@ static int do_fetch(struct transport *transport,
|
||||
die("Don't know how to fetch from %s", transport->url);
|
||||
|
||||
/* if not appending, truncate FETCH_HEAD */
|
||||
if (!append) {
|
||||
if (!append && !dry_run) {
|
||||
char *filename = git_path("FETCH_HEAD");
|
||||
FILE *fp = fopen(filename, "w");
|
||||
if (!fp)
|
||||
@@ -661,6 +696,8 @@ static int do_fetch(struct transport *transport,
|
||||
free_refs(ref_map);
|
||||
return 1;
|
||||
}
|
||||
if (prune)
|
||||
prune_refs(transport, ref_map);
|
||||
free_refs(ref_map);
|
||||
|
||||
/* if neither --no-tags nor --tags was specified, do automated tag
|
||||
@@ -691,27 +728,94 @@ static void set_option(const char *name, const char *value)
|
||||
name, transport->url);
|
||||
}
|
||||
|
||||
int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
static int get_one_remote_for_fetch(struct remote *remote, void *priv)
|
||||
{
|
||||
struct string_list *list = priv;
|
||||
if (!remote->skip_default_update)
|
||||
string_list_append(remote->name, list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct remote_group_data {
|
||||
const char *name;
|
||||
struct string_list *list;
|
||||
};
|
||||
|
||||
static int get_remote_group(const char *key, const char *value, void *priv)
|
||||
{
|
||||
struct remote_group_data *g = priv;
|
||||
|
||||
if (!prefixcmp(key, "remotes.") &&
|
||||
!strcmp(key + 8, g->name)) {
|
||||
/* split list by white space */
|
||||
int space = strcspn(value, " \t\n");
|
||||
while (*value) {
|
||||
if (space > 1) {
|
||||
string_list_append(xstrndup(value, space),
|
||||
g->list);
|
||||
}
|
||||
value += space + (value[space] != '\0');
|
||||
space = strcspn(value, " \t\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_remote_or_group(const char *name, struct string_list *list)
|
||||
{
|
||||
int prev_nr = list->nr;
|
||||
struct remote_group_data g = { name, list };
|
||||
|
||||
git_config(get_remote_group, &g);
|
||||
if (list->nr == prev_nr) {
|
||||
struct remote *remote;
|
||||
if (!remote_is_configured(name))
|
||||
return 0;
|
||||
remote = remote_get(name);
|
||||
string_list_append(remote->name, list);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fetch_multiple(struct string_list *list)
|
||||
{
|
||||
int i, result = 0;
|
||||
const char *argv[] = { "fetch", NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
int argc = 1;
|
||||
|
||||
if (dry_run)
|
||||
argv[argc++] = "--dry-run";
|
||||
if (prune)
|
||||
argv[argc++] = "--prune";
|
||||
if (verbosity >= 2)
|
||||
argv[argc++] = "-v";
|
||||
if (verbosity >= 1)
|
||||
argv[argc++] = "-v";
|
||||
else if (verbosity < 0)
|
||||
argv[argc++] = "-q";
|
||||
|
||||
for (i = 0; i < list->nr; i++) {
|
||||
const char *name = list->items[i].string;
|
||||
argv[argc] = name;
|
||||
if (verbosity >= 0)
|
||||
printf("Fetching %s\n", name);
|
||||
if (run_command_v_opt(argv, RUN_GIT_CMD)) {
|
||||
error("Could not fetch %s", name);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fetch_one(struct remote *remote, int argc, const char **argv)
|
||||
{
|
||||
struct remote *remote;
|
||||
int i;
|
||||
static const char **refs = NULL;
|
||||
int ref_nr = 0;
|
||||
int exit_code;
|
||||
|
||||
/* Record the command line for the reflog */
|
||||
strbuf_addstr(&default_rla, "fetch");
|
||||
for (i = 1; i < argc; i++)
|
||||
strbuf_addf(&default_rla, " %s", argv[i]);
|
||||
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_fetch_options, builtin_fetch_usage, 0);
|
||||
|
||||
if (argc == 0)
|
||||
remote = remote_get(NULL);
|
||||
else
|
||||
remote = remote_get(argv[0]);
|
||||
|
||||
if (!remote)
|
||||
die("Where do you want to fetch from today?");
|
||||
|
||||
@@ -727,10 +831,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
if (depth)
|
||||
set_option(TRANS_OPT_DEPTH, depth);
|
||||
|
||||
if (argc > 1) {
|
||||
if (argc > 0) {
|
||||
int j = 0;
|
||||
refs = xcalloc(argc + 1, sizeof(const char *));
|
||||
for (i = 1; i < argc; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "tag")) {
|
||||
char *ref;
|
||||
i++;
|
||||
@@ -757,3 +861,57 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
transport = NULL;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
struct string_list list = { NULL, 0, 0, 0 };
|
||||
struct remote *remote;
|
||||
int result = 0;
|
||||
|
||||
/* Record the command line for the reflog */
|
||||
strbuf_addstr(&default_rla, "fetch");
|
||||
for (i = 1; i < argc; i++)
|
||||
strbuf_addf(&default_rla, " %s", argv[i]);
|
||||
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_fetch_options, builtin_fetch_usage, 0);
|
||||
|
||||
if (all) {
|
||||
if (argc == 1)
|
||||
die("fetch --all does not take a repository argument");
|
||||
else if (argc > 1)
|
||||
die("fetch --all does not make sense with refspecs");
|
||||
(void) for_each_remote(get_one_remote_for_fetch, &list);
|
||||
result = fetch_multiple(&list);
|
||||
} else if (argc == 0) {
|
||||
/* No arguments -- use default remote */
|
||||
remote = remote_get(NULL);
|
||||
result = fetch_one(remote, argc, argv);
|
||||
} else if (multiple) {
|
||||
/* All arguments are assumed to be remotes or groups */
|
||||
for (i = 0; i < argc; i++)
|
||||
if (!add_remote_or_group(argv[i], &list))
|
||||
die("No such remote or remote group: %s", argv[i]);
|
||||
result = fetch_multiple(&list);
|
||||
} else {
|
||||
/* Single remote or group */
|
||||
(void) add_remote_or_group(argv[0], &list);
|
||||
if (list.nr > 1) {
|
||||
/* More than one remote */
|
||||
if (argc > 1)
|
||||
die("Fetching a group and specifying refspecs does not make sense");
|
||||
result = fetch_multiple(&list);
|
||||
} else {
|
||||
/* Zero or one remotes */
|
||||
remote = remote_get(argv[0]);
|
||||
result = fetch_one(remote, argc-1, argv+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* All names were strdup()ed or strndup()ed */
|
||||
list.strdup_strings = 1;
|
||||
string_list_clear(&list, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -427,9 +427,6 @@ int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
setup_git_directory_gently(&nongit);
|
||||
git_config(git_help_config, NULL);
|
||||
|
||||
if (!argv[0]) {
|
||||
printf("usage: %s\n\n", git_usage_string);
|
||||
list_common_cmds_help();
|
||||
@@ -437,6 +434,9 @@ int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
setup_git_directory_gently(&nongit);
|
||||
git_config(git_help_config, NULL);
|
||||
|
||||
alias = alias_lookup(argv[0]);
|
||||
if (alias && !is_git_command(argv[0])) {
|
||||
printf("`git %s' is aliased to `%s'\n", argv[0], alias);
|
||||
|
||||
@@ -976,7 +976,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
|
||||
builtin_format_patch_usage,
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
|
||||
if (do_signoff) {
|
||||
const char *committer;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
static FILE *cmitmsg, *patchfile, *fin, *fout;
|
||||
|
||||
static int keep_subject;
|
||||
static int keep_non_patch_brackets_in_subject;
|
||||
static const char *metainfo_charset;
|
||||
static struct strbuf line = STRBUF_INIT;
|
||||
static struct strbuf name = STRBUF_INIT;
|
||||
@@ -221,35 +222,41 @@ static int is_multipart_boundary(const struct strbuf *line)
|
||||
|
||||
static void cleanup_subject(struct strbuf *subject)
|
||||
{
|
||||
char *pos;
|
||||
size_t remove;
|
||||
while (subject->len) {
|
||||
switch (*subject->buf) {
|
||||
size_t at = 0;
|
||||
|
||||
while (at < subject->len) {
|
||||
char *pos;
|
||||
size_t remove;
|
||||
|
||||
switch (subject->buf[at]) {
|
||||
case 'r': case 'R':
|
||||
if (subject->len <= 3)
|
||||
if (subject->len <= at + 3)
|
||||
break;
|
||||
if (!memcmp(subject->buf + 1, "e:", 2)) {
|
||||
strbuf_remove(subject, 0, 3);
|
||||
if (!memcmp(subject->buf + at + 1, "e:", 2)) {
|
||||
strbuf_remove(subject, at, 3);
|
||||
continue;
|
||||
}
|
||||
at++;
|
||||
break;
|
||||
case ' ': case '\t': case ':':
|
||||
strbuf_remove(subject, 0, 1);
|
||||
strbuf_remove(subject, at, 1);
|
||||
continue;
|
||||
case '[':
|
||||
if ((pos = strchr(subject->buf, ']'))) {
|
||||
remove = pos - subject->buf;
|
||||
if (remove <= (subject->len - remove) * 2) {
|
||||
strbuf_remove(subject, 0, remove + 1);
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
strbuf_remove(subject, 0, 1);
|
||||
break;
|
||||
pos = strchr(subject->buf + at, ']');
|
||||
if (!pos)
|
||||
break;
|
||||
remove = pos - subject->buf + at + 1;
|
||||
if (!keep_non_patch_brackets_in_subject ||
|
||||
(7 <= remove &&
|
||||
memmem(subject->buf + at, remove, "PATCH", 5)))
|
||||
strbuf_remove(subject, at, remove);
|
||||
else
|
||||
at += remove;
|
||||
continue;
|
||||
}
|
||||
strbuf_trim(subject);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
strbuf_trim(subject);
|
||||
}
|
||||
|
||||
static void cleanup_space(struct strbuf *sb)
|
||||
@@ -1014,7 +1021,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)
|
||||
}
|
||||
|
||||
static const char mailinfo_usage[] =
|
||||
"git mailinfo [-k] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
|
||||
"git mailinfo [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
|
||||
|
||||
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
@@ -1031,6 +1038,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
|
||||
while (1 < argc && argv[1][0] == '-') {
|
||||
if (!strcmp(argv[1], "-k"))
|
||||
keep_subject = 1;
|
||||
else if (!strcmp(argv[1], "-b"))
|
||||
keep_non_patch_brackets_in_subject = 1;
|
||||
else if (!strcmp(argv[1], "-u"))
|
||||
metainfo_charset = def_charset;
|
||||
else if (!strcmp(argv[1], "-n"))
|
||||
|
||||
@@ -71,7 +71,7 @@ static int option_parse_message(const struct option *opt,
|
||||
if (unset)
|
||||
strbuf_setlen(buf, 0);
|
||||
else if (arg) {
|
||||
strbuf_addf(buf, "%s\n\n", arg);
|
||||
strbuf_addf(buf, "%s%s", buf->len ? "\n\n" : "", arg);
|
||||
have_message = 1;
|
||||
} else
|
||||
return error("switch `m' requires a value");
|
||||
@@ -107,8 +107,8 @@ static struct strategy *get_strategy(const char *name)
|
||||
found = 1;
|
||||
if (!found)
|
||||
add_cmdname(¬_strategies, ent->name, ent->len);
|
||||
exclude_cmds(&main_cmds, ¬_strategies);
|
||||
}
|
||||
exclude_cmds(&main_cmds, ¬_strategies);
|
||||
}
|
||||
if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
|
||||
fprintf(stderr, "Could not find merge strategy '%s'.\n", name);
|
||||
@@ -656,6 +656,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
|
||||
opts.verbose_update = 1;
|
||||
opts.merge = 1;
|
||||
opts.fn = twoway_merge;
|
||||
opts.msgs = get_porcelain_error_msgs();
|
||||
|
||||
trees[nr_trees] = parse_tree_indirect(head);
|
||||
if (!trees[nr_trees++])
|
||||
@@ -795,10 +796,15 @@ static int suggest_conflicts(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char deprecation_warning[] =
|
||||
"'git merge <msg> HEAD <commit>' is deprecated. Please update\n"
|
||||
"your script to use 'git merge -m <msg> <commit>' instead.\n"
|
||||
"In future versions of git, this syntax will be removed.";
|
||||
|
||||
static struct commit *is_old_style_invocation(int argc, const char **argv)
|
||||
{
|
||||
struct commit *second_token = NULL;
|
||||
if (argc > 1) {
|
||||
if (argc > 2) {
|
||||
unsigned char second_sha1[20];
|
||||
|
||||
if (get_sha1(argv[1], second_sha1))
|
||||
@@ -808,6 +814,7 @@ static struct commit *is_old_style_invocation(int argc, const char **argv)
|
||||
die("'%s' is not a commit", argv[1]);
|
||||
if (hashcmp(second_token->object.sha1, head))
|
||||
return NULL;
|
||||
warning(deprecation_warning);
|
||||
}
|
||||
return second_token;
|
||||
}
|
||||
@@ -936,11 +943,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||
* codepath so we discard the error in this
|
||||
* loop.
|
||||
*/
|
||||
for (i = 0; i < argc; i++)
|
||||
merge_name(argv[i], &msg);
|
||||
fmt_merge_msg(option_log, &msg, &merge_msg);
|
||||
if (merge_msg.len)
|
||||
strbuf_setlen(&merge_msg, merge_msg.len-1);
|
||||
if (!have_message) {
|
||||
for (i = 0; i < argc; i++)
|
||||
merge_name(argv[i], &msg);
|
||||
fmt_merge_msg(option_log, &msg, &merge_msg);
|
||||
if (merge_msg.len)
|
||||
strbuf_setlen(&merge_msg, merge_msg.len-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (head_invalid || !argc)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
static const char pack_usage[] =
|
||||
"git pack-objects [{ -q | --progress | --all-progress }]\n"
|
||||
" [--all-progress-implied]\n"
|
||||
" [--max-pack-size=N] [--local] [--incremental]\n"
|
||||
" [--window=N] [--window-memory=N] [--depth=N]\n"
|
||||
" [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n"
|
||||
@@ -2124,6 +2125,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int use_internal_rev_list = 0;
|
||||
int thin = 0;
|
||||
int all_progress_implied = 0;
|
||||
uint32_t i;
|
||||
const char **rp_av;
|
||||
int rp_ac_alloc = 64;
|
||||
@@ -2223,6 +2225,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
progress = 2;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--all-progress-implied", arg)) {
|
||||
all_progress_implied = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-q", arg)) {
|
||||
progress = 0;
|
||||
continue;
|
||||
@@ -2326,6 +2332,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
if (keep_unreachable && unpack_unreachable)
|
||||
die("--keep-unreachable and --unpack-unreachable are incompatible.");
|
||||
|
||||
if (progress && all_progress_implied)
|
||||
progress = 2;
|
||||
|
||||
prepare_packed_git();
|
||||
|
||||
if (progress)
|
||||
|
||||
@@ -71,7 +71,7 @@ void prune_packed_objects(int opts)
|
||||
|
||||
int cmd_prune_packed(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int opts = VERBOSE;
|
||||
int opts = isatty(2) ? VERBOSE : 0;
|
||||
const struct option prune_packed_options[] = {
|
||||
OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN),
|
||||
OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE),
|
||||
|
||||
128
builtin-remote.c
128
builtin-remote.c
@@ -261,32 +261,10 @@ struct ref_states {
|
||||
int queried;
|
||||
};
|
||||
|
||||
static int handle_one_branch(const char *refname,
|
||||
const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct ref_states *states = cb_data;
|
||||
struct refspec refspec;
|
||||
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
if (!remote_find_tracking(states->remote, &refspec)) {
|
||||
struct string_list_item *item;
|
||||
const char *name = abbrev_branch(refspec.src);
|
||||
/* symbolic refs pointing nowhere were handled already */
|
||||
if ((flags & REF_ISSYMREF) ||
|
||||
string_list_has_string(&states->tracked, name) ||
|
||||
string_list_has_string(&states->new, name))
|
||||
return 0;
|
||||
item = string_list_append(name, &states->stale);
|
||||
item->util = xstrdup(refname);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
|
||||
{
|
||||
struct ref *fetch_map = NULL, **tail = &fetch_map;
|
||||
struct ref *ref;
|
||||
struct ref *ref, *stale_refs;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < states->remote->fetch_refspec_nr; i++)
|
||||
@@ -294,7 +272,9 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
|
||||
die("Could not get fetch map for refspec %s",
|
||||
states->remote->fetch_refspec[i]);
|
||||
|
||||
states->new.strdup_strings = states->tracked.strdup_strings = 1;
|
||||
states->new.strdup_strings = 1;
|
||||
states->tracked.strdup_strings = 1;
|
||||
states->stale.strdup_strings = 1;
|
||||
for (ref = fetch_map; ref; ref = ref->next) {
|
||||
unsigned char sha1[20];
|
||||
if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))
|
||||
@@ -302,11 +282,17 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
|
||||
else
|
||||
string_list_append(abbrev_branch(ref->name), &states->tracked);
|
||||
}
|
||||
stale_refs = get_stale_heads(states->remote, fetch_map);
|
||||
for (ref = stale_refs; ref; ref = ref->next) {
|
||||
struct string_list_item *item =
|
||||
string_list_append(abbrev_branch(ref->name), &states->stale);
|
||||
item->util = xstrdup(ref->name);
|
||||
}
|
||||
free_refs(stale_refs);
|
||||
free_refs(fetch_map);
|
||||
|
||||
sort_string_list(&states->new);
|
||||
sort_string_list(&states->tracked);
|
||||
for_each_ref(handle_one_branch, states);
|
||||
sort_string_list(&states->stale);
|
||||
|
||||
return 0;
|
||||
@@ -784,7 +770,7 @@ static void clear_push_info(void *util, const char *string)
|
||||
static void free_remote_ref_states(struct ref_states *states)
|
||||
{
|
||||
string_list_clear(&states->new, 0);
|
||||
string_list_clear(&states->stale, 0);
|
||||
string_list_clear(&states->stale, 1);
|
||||
string_list_clear(&states->tracked, 0);
|
||||
string_list_clear(&states->heads, 0);
|
||||
string_list_clear_func(&states->push, clear_push_info);
|
||||
@@ -1213,94 +1199,62 @@ static int prune_remote(const char *remote, int dry_run)
|
||||
|
||||
printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
|
||||
abbrev_ref(refname, "refs/remotes/"));
|
||||
warn_dangling_symref(dangling_msg, refname);
|
||||
warn_dangling_symref(stdout, dangling_msg, refname);
|
||||
}
|
||||
|
||||
free_remote_ref_states(&states);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int get_one_remote_for_update(struct remote *remote, void *priv)
|
||||
static int get_remote_default(const char *key, const char *value, void *priv)
|
||||
{
|
||||
struct string_list *list = priv;
|
||||
if (!remote->skip_default_update)
|
||||
string_list_append(remote->name, list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct remote_group {
|
||||
const char *name;
|
||||
struct string_list *list;
|
||||
} remote_group;
|
||||
|
||||
static int get_remote_group(const char *key, const char *value, void *num_hits)
|
||||
{
|
||||
if (!prefixcmp(key, "remotes.") &&
|
||||
!strcmp(key + 8, remote_group.name)) {
|
||||
/* split list by white space */
|
||||
int space = strcspn(value, " \t\n");
|
||||
while (*value) {
|
||||
if (space > 1) {
|
||||
string_list_append(xstrndup(value, space),
|
||||
remote_group.list);
|
||||
++*((int *)num_hits);
|
||||
}
|
||||
value += space + (value[space] != '\0');
|
||||
space = strcspn(value, " \t\n");
|
||||
}
|
||||
if (strcmp(key, "remotes.default") == 0) {
|
||||
int *found = priv;
|
||||
*found = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update(int argc, const char **argv)
|
||||
{
|
||||
int i, result = 0, prune = 0;
|
||||
struct string_list list = { NULL, 0, 0, 0 };
|
||||
static const char *default_argv[] = { NULL, "default", NULL };
|
||||
int i, prune = 0;
|
||||
struct option options[] = {
|
||||
OPT_BOOLEAN('p', "prune", &prune,
|
||||
"prune remotes after fetching"),
|
||||
OPT_END()
|
||||
};
|
||||
const char **fetch_argv;
|
||||
int fetch_argc = 0;
|
||||
int default_defined = 0;
|
||||
|
||||
fetch_argv = xmalloc(sizeof(char *) * (argc+5));
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
|
||||
PARSE_OPT_KEEP_ARGV0);
|
||||
|
||||
fetch_argv[fetch_argc++] = "fetch";
|
||||
|
||||
if (prune)
|
||||
fetch_argv[fetch_argc++] = "--prune";
|
||||
if (verbose)
|
||||
fetch_argv[fetch_argc++] = "-v";
|
||||
if (argc < 2) {
|
||||
argc = 2;
|
||||
argv = default_argv;
|
||||
fetch_argv[fetch_argc++] = "default";
|
||||
} else {
|
||||
fetch_argv[fetch_argc++] = "--multiple";
|
||||
for (i = 1; i < argc; i++)
|
||||
fetch_argv[fetch_argc++] = argv[i];
|
||||
}
|
||||
|
||||
remote_group.list = &list;
|
||||
for (i = 1; i < argc; i++) {
|
||||
int groups_found = 0;
|
||||
remote_group.name = argv[i];
|
||||
result = git_config(get_remote_group, &groups_found);
|
||||
if (!groups_found && (i != 1 || strcmp(argv[1], "default"))) {
|
||||
struct remote *remote;
|
||||
if (!remote_is_configured(argv[i]))
|
||||
die("No such remote or remote group: %s",
|
||||
argv[i]);
|
||||
remote = remote_get(argv[i]);
|
||||
string_list_append(remote->name, remote_group.list);
|
||||
}
|
||||
if (strcmp(fetch_argv[fetch_argc-1], "default") == 0) {
|
||||
git_config(get_remote_default, &default_defined);
|
||||
if (!default_defined)
|
||||
fetch_argv[fetch_argc-1] = "--all";
|
||||
}
|
||||
|
||||
if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default"))
|
||||
result = for_each_remote(get_one_remote_for_update, &list);
|
||||
fetch_argv[fetch_argc] = NULL;
|
||||
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
int err = fetch_remote(list.items[i].string);
|
||||
result |= err;
|
||||
if (!err && prune)
|
||||
result |= prune_remote(list.items[i].string, 0);
|
||||
}
|
||||
|
||||
/* all names were strdup()ed or strndup()ed */
|
||||
list.strdup_strings = 1;
|
||||
string_list_clear(&list, 0);
|
||||
|
||||
return result;
|
||||
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
|
||||
}
|
||||
|
||||
static int get_one_entry(struct remote *remote, void *priv)
|
||||
|
||||
@@ -306,7 +306,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
struct rev_info revs;
|
||||
struct rev_list_info info;
|
||||
int i;
|
||||
int read_from_stdin = 0;
|
||||
int bisect_list = 0;
|
||||
int bisect_show_vars = 0;
|
||||
int bisect_find_all = 0;
|
||||
@@ -351,12 +350,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
bisect_show_vars = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--stdin")) {
|
||||
if (read_from_stdin++)
|
||||
die("--stdin given twice?");
|
||||
read_revisions_from_stdin(&revs);
|
||||
continue;
|
||||
}
|
||||
usage(rev_list_usage);
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
|
||||
*/
|
||||
const char *argv[] = {
|
||||
"pack-objects",
|
||||
"--all-progress",
|
||||
"--all-progress-implied",
|
||||
"--revs",
|
||||
"--stdout",
|
||||
NULL,
|
||||
|
||||
@@ -139,8 +139,12 @@ static void read_from_stdin(struct shortlog *log)
|
||||
void shortlog_add_commit(struct shortlog *log, struct commit *commit)
|
||||
{
|
||||
const char *author = NULL, *buffer;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct strbuf ufbuf = STRBUF_INIT;
|
||||
struct pretty_print_context ctx = {0};
|
||||
|
||||
buffer = commit->buffer;
|
||||
pretty_print_commit(CMIT_FMT_RAW, commit, &buf, &ctx);
|
||||
buffer = buf.buf;
|
||||
while (*buffer && *buffer != '\n') {
|
||||
const char *eol = strchr(buffer, '\n');
|
||||
|
||||
@@ -157,20 +161,19 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
|
||||
die("Missing author: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
if (log->user_format) {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct pretty_print_context ctx = {0};
|
||||
ctx.abbrev = DEFAULT_ABBREV;
|
||||
ctx.subject = "";
|
||||
ctx.after_subject = "";
|
||||
ctx.date_mode = DATE_NORMAL;
|
||||
pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf, &ctx);
|
||||
insert_one_record(log, author, buf.buf);
|
||||
strbuf_release(&buf);
|
||||
return;
|
||||
}
|
||||
if (*buffer)
|
||||
pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &ufbuf, &ctx);
|
||||
buffer = ufbuf.buf;
|
||||
} else if (*buffer) {
|
||||
buffer++;
|
||||
}
|
||||
insert_one_record(log, author, !*buffer ? "<none>" : buffer);
|
||||
strbuf_release(&ufbuf);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
static void get_from_rev(struct rev_info *rev, struct shortlog *log)
|
||||
|
||||
14
bundle.c
14
bundle.c
@@ -204,7 +204,6 @@ int create_bundle(struct bundle_header *header, const char *path,
|
||||
int i, ref_count = 0;
|
||||
char buffer[1024];
|
||||
struct rev_info revs;
|
||||
int read_from_stdin = 0;
|
||||
struct child_process rls;
|
||||
FILE *rls_fout;
|
||||
|
||||
@@ -256,15 +255,8 @@ int create_bundle(struct bundle_header *header, const char *path,
|
||||
/* write references */
|
||||
argc = setup_revisions(argc, argv, &revs, NULL);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--stdin")) {
|
||||
if (read_from_stdin++)
|
||||
die("--stdin given twice?");
|
||||
read_revisions_from_stdin(&revs);
|
||||
continue;
|
||||
}
|
||||
return error("unrecognized argument: %s'", argv[i]);
|
||||
}
|
||||
if (argc > 1)
|
||||
return error("unrecognized argument: %s'", argv[1]);
|
||||
|
||||
object_array_remove_duplicates(&revs.pending);
|
||||
|
||||
@@ -351,7 +343,7 @@ int create_bundle(struct bundle_header *header, const char *path,
|
||||
|
||||
/* write pack */
|
||||
argv_pack[0] = "pack-objects";
|
||||
argv_pack[1] = "--all-progress";
|
||||
argv_pack[1] = "--all-progress-implied";
|
||||
argv_pack[2] = "--stdout";
|
||||
argv_pack[3] = "--thin";
|
||||
argv_pack[4] = NULL;
|
||||
|
||||
1
cache.h
1
cache.h
@@ -369,6 +369,7 @@ static inline enum object_type object_type(unsigned int mode)
|
||||
#define CONFIG_ENVIRONMENT "GIT_CONFIG"
|
||||
#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
|
||||
#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
|
||||
#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
|
||||
#define GITATTRIBUTES_FILE ".gitattributes"
|
||||
#define INFOATTRIBUTES_FILE "info/attributes"
|
||||
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
|
||||
|
||||
5
color.h
5
color.h
@@ -4,6 +4,11 @@
|
||||
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
|
||||
#define COLOR_MAXLEN 24
|
||||
|
||||
/*
|
||||
* IMPORTANT: Due to the way these color codes are emulated on Windows,
|
||||
* write them only using printf(), fprintf(), and fputs(). In particular,
|
||||
* do not use puts() or write().
|
||||
*/
|
||||
#define GIT_COLOR_NORMAL ""
|
||||
#define GIT_COLOR_RESET "\033[m"
|
||||
#define GIT_COLOR_BOLD "\033[1m"
|
||||
|
||||
@@ -524,6 +524,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
|
||||
int i;
|
||||
unsigned long lno = 0;
|
||||
const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO);
|
||||
const char *c_func = diff_get_color(use_color, DIFF_FUNCINFO);
|
||||
const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW);
|
||||
const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD);
|
||||
const char *c_plain = diff_get_color(use_color, DIFF_PLAIN);
|
||||
@@ -588,7 +589,9 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
|
||||
comment_end = i;
|
||||
}
|
||||
if (comment_end)
|
||||
putchar(' ');
|
||||
printf("%s%s %s%s", c_reset,
|
||||
c_plain, c_reset,
|
||||
c_func);
|
||||
for (i = 0; i < comment_end; i++)
|
||||
putchar(hunk_comment[i]);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ static inline uint32_t default_swab32(uint32_t val)
|
||||
if (__builtin_constant_p(x)) { \
|
||||
__res = default_swab32(x); \
|
||||
} else { \
|
||||
__asm__("bswap %0" : "=r" (__res) : "0" (x)); \
|
||||
__asm__("bswap %0" : "=r" (__res) : "0" ((uint32_t)(x))); \
|
||||
} \
|
||||
__res; })
|
||||
|
||||
|
||||
184
compat/mingw.c
184
compat/mingw.c
@@ -903,19 +903,195 @@ char **make_augmented_environ(const char *const *vars)
|
||||
return env;
|
||||
}
|
||||
|
||||
/* this is the first function to call into WS_32; initialize it */
|
||||
#undef gethostbyname
|
||||
struct hostent *mingw_gethostbyname(const char *host)
|
||||
/*
|
||||
* Note, this isn't a complete replacement for getaddrinfo. It assumes
|
||||
* that service contains a numerical port, or that it it is null. It
|
||||
* does a simple search using gethostbyname, and returns one IPv4 host
|
||||
* if one was found.
|
||||
*/
|
||||
static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
struct hostent *h = gethostbyname(node);
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
if (!h)
|
||||
return WSAGetLastError();
|
||||
|
||||
ai = xmalloc(sizeof(struct addrinfo));
|
||||
*res = ai;
|
||||
ai->ai_flags = 0;
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
switch (hints->ai_socktype) {
|
||||
case SOCK_STREAM:
|
||||
ai->ai_protocol = IPPROTO_TCP;
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
ai->ai_protocol = IPPROTO_UDP;
|
||||
break;
|
||||
default:
|
||||
ai->ai_protocol = 0;
|
||||
break;
|
||||
}
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_canonname = strdup(h->h_name);
|
||||
|
||||
sin = xmalloc(ai->ai_addrlen);
|
||||
memset(sin, 0, ai->ai_addrlen);
|
||||
sin->sin_family = AF_INET;
|
||||
if (service)
|
||||
sin->sin_port = htons(atoi(service));
|
||||
sin->sin_addr = *(struct in_addr *)h->h_addr;
|
||||
ai->ai_addr = (struct sockaddr *)sin;
|
||||
ai->ai_next = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void WSAAPI freeaddrinfo_stub(struct addrinfo *res)
|
||||
{
|
||||
free(res->ai_canonname);
|
||||
free(res->ai_addr);
|
||||
free(res);
|
||||
}
|
||||
|
||||
static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen,
|
||||
char *host, DWORD hostlen,
|
||||
char *serv, DWORD servlen, int flags)
|
||||
{
|
||||
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
|
||||
if (sa->sa_family != AF_INET)
|
||||
return EAI_FAMILY;
|
||||
if (!host && !serv)
|
||||
return EAI_NONAME;
|
||||
|
||||
if (host && hostlen > 0) {
|
||||
struct hostent *ent = NULL;
|
||||
if (!(flags & NI_NUMERICHOST))
|
||||
ent = gethostbyaddr((const char *)&sin->sin_addr,
|
||||
sizeof(sin->sin_addr), AF_INET);
|
||||
|
||||
if (ent)
|
||||
snprintf(host, hostlen, "%s", ent->h_name);
|
||||
else if (flags & NI_NAMEREQD)
|
||||
return EAI_NONAME;
|
||||
else
|
||||
snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
|
||||
}
|
||||
|
||||
if (serv && servlen > 0) {
|
||||
struct servent *ent = NULL;
|
||||
if (!(flags & NI_NUMERICSERV))
|
||||
ent = getservbyport(sin->sin_port,
|
||||
flags & NI_DGRAM ? "udp" : "tcp");
|
||||
|
||||
if (ent)
|
||||
snprintf(serv, servlen, "%s", ent->s_name);
|
||||
else
|
||||
snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HMODULE ipv6_dll = NULL;
|
||||
static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res);
|
||||
static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res);
|
||||
static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
|
||||
char *host, DWORD hostlen,
|
||||
char *serv, DWORD servlen, int flags);
|
||||
/*
|
||||
* gai_strerror is an inline function in the ws2tcpip.h header, so we
|
||||
* don't need to try to load that one dynamically.
|
||||
*/
|
||||
|
||||
static void socket_cleanup(void)
|
||||
{
|
||||
WSACleanup();
|
||||
if (ipv6_dll)
|
||||
FreeLibrary(ipv6_dll);
|
||||
ipv6_dll = NULL;
|
||||
ipv6_freeaddrinfo = freeaddrinfo_stub;
|
||||
ipv6_getaddrinfo = getaddrinfo_stub;
|
||||
ipv6_getnameinfo = getnameinfo_stub;
|
||||
}
|
||||
|
||||
static void ensure_socket_initialization(void)
|
||||
{
|
||||
WSADATA wsa;
|
||||
static int initialized = 0;
|
||||
const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
|
||||
const char **name;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsa))
|
||||
die("unable to initialize winsock subsystem, error %d",
|
||||
WSAGetLastError());
|
||||
atexit((void(*)(void)) WSACleanup);
|
||||
|
||||
for (name = libraries; *name; name++) {
|
||||
ipv6_dll = LoadLibrary(*name);
|
||||
if (!ipv6_dll)
|
||||
continue;
|
||||
|
||||
ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *))
|
||||
GetProcAddress(ipv6_dll, "freeaddrinfo");
|
||||
ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *,
|
||||
const struct addrinfo *,
|
||||
struct addrinfo **))
|
||||
GetProcAddress(ipv6_dll, "getaddrinfo");
|
||||
ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *,
|
||||
socklen_t, char *, DWORD,
|
||||
char *, DWORD, int))
|
||||
GetProcAddress(ipv6_dll, "getnameinfo");
|
||||
if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
|
||||
FreeLibrary(ipv6_dll);
|
||||
ipv6_dll = NULL;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
|
||||
ipv6_freeaddrinfo = freeaddrinfo_stub;
|
||||
ipv6_getaddrinfo = getaddrinfo_stub;
|
||||
ipv6_getnameinfo = getnameinfo_stub;
|
||||
}
|
||||
|
||||
atexit(socket_cleanup);
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
#undef gethostbyname
|
||||
struct hostent *mingw_gethostbyname(const char *host)
|
||||
{
|
||||
ensure_socket_initialization();
|
||||
return gethostbyname(host);
|
||||
}
|
||||
|
||||
void mingw_freeaddrinfo(struct addrinfo *res)
|
||||
{
|
||||
ipv6_freeaddrinfo(res);
|
||||
}
|
||||
|
||||
int mingw_getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
ensure_socket_initialization();
|
||||
return ipv6_getaddrinfo(node, service, hints, res);
|
||||
}
|
||||
|
||||
int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
char *host, DWORD hostlen, char *serv, DWORD servlen,
|
||||
int flags)
|
||||
{
|
||||
ensure_socket_initialization();
|
||||
return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
||||
}
|
||||
|
||||
int mingw_socket(int domain, int type, int protocol)
|
||||
{
|
||||
int sockfd;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
/*
|
||||
* things that are not available in header files
|
||||
@@ -178,6 +179,18 @@ char *mingw_getenv(const char *name);
|
||||
struct hostent *mingw_gethostbyname(const char *host);
|
||||
#define gethostbyname mingw_gethostbyname
|
||||
|
||||
void mingw_freeaddrinfo(struct addrinfo *res);
|
||||
#define freeaddrinfo mingw_freeaddrinfo
|
||||
|
||||
int mingw_getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
#define getaddrinfo mingw_getaddrinfo
|
||||
|
||||
int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
char *host, DWORD hostlen, char *serv, DWORD servlen,
|
||||
int flags);
|
||||
#define getnameinfo mingw_getnameinfo
|
||||
|
||||
int mingw_socket(int domain, int type, int protocol);
|
||||
#define socket mingw_socket
|
||||
|
||||
|
||||
@@ -609,6 +609,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
||||
GIT_WORK_TREE_ENVIRONMENT,
|
||||
GRAFT_ENVIRONMENT,
|
||||
INDEX_ENVIRONMENT,
|
||||
NO_REPLACE_OBJECTS_ENVIRONMENT,
|
||||
NULL
|
||||
};
|
||||
conn->env = env;
|
||||
|
||||
56
diff.c
56
diff.c
@@ -39,6 +39,7 @@ static char diff_colors[][COLOR_MAXLEN] = {
|
||||
GIT_COLOR_GREEN, /* NEW */
|
||||
GIT_COLOR_YELLOW, /* COMMIT */
|
||||
GIT_COLOR_BG_RED, /* WHITESPACE */
|
||||
GIT_COLOR_NORMAL, /* FUNCINFO */
|
||||
};
|
||||
|
||||
static void diff_filespec_load_driver(struct diff_filespec *one);
|
||||
@@ -60,6 +61,8 @@ static int parse_diff_color_slot(const char *var, int ofs)
|
||||
return DIFF_COMMIT;
|
||||
if (!strcasecmp(var+ofs, "whitespace"))
|
||||
return DIFF_WHITESPACE;
|
||||
if (!strcasecmp(var+ofs, "func"))
|
||||
return DIFF_FUNCINFO;
|
||||
die("bad config variable '%s'", var);
|
||||
}
|
||||
|
||||
@@ -295,12 +298,13 @@ static void emit_line_0(FILE *file, const char *set, const char *reset,
|
||||
nofirst = 0;
|
||||
}
|
||||
|
||||
fputs(set, file);
|
||||
|
||||
if (!nofirst)
|
||||
fputc(first, file);
|
||||
fwrite(line, len, 1, file);
|
||||
fputs(reset, file);
|
||||
if (len || !nofirst) {
|
||||
fputs(set, file);
|
||||
if (!nofirst)
|
||||
fputc(first, file);
|
||||
fwrite(line, len, 1, file);
|
||||
fputs(reset, file);
|
||||
}
|
||||
if (has_trailing_carriage_return)
|
||||
fputc('\r', file);
|
||||
if (has_trailing_newline)
|
||||
@@ -344,6 +348,42 @@ static void emit_add_line(const char *reset,
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_hunk_header(struct emit_callback *ecbdata,
|
||||
const char *line, int len)
|
||||
{
|
||||
const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
|
||||
const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);
|
||||
const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO);
|
||||
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
|
||||
static const char atat[2] = { '@', '@' };
|
||||
const char *cp, *ep;
|
||||
|
||||
/*
|
||||
* As a hunk header must begin with "@@ -<old>, +<new> @@",
|
||||
* it always is at least 10 bytes long.
|
||||
*/
|
||||
if (len < 10 ||
|
||||
memcmp(line, atat, 2) ||
|
||||
!(ep = memmem(line + 2, len - 2, atat, 2))) {
|
||||
emit_line(ecbdata->file, plain, reset, line, len);
|
||||
return;
|
||||
}
|
||||
ep += 2; /* skip over @@ */
|
||||
|
||||
/* The hunk header in fraginfo color */
|
||||
emit_line(ecbdata->file, frag, reset, line, ep - line);
|
||||
|
||||
/* blank before the func header */
|
||||
for (cp = ep; ep - line < len; ep++)
|
||||
if (*ep != ' ' && *ep != '\t')
|
||||
break;
|
||||
if (ep != cp)
|
||||
emit_line(ecbdata->file, plain, reset, cp, ep - cp);
|
||||
|
||||
if (ep < line + len)
|
||||
emit_line(ecbdata->file, func, reset, ep, line + len - ep);
|
||||
}
|
||||
|
||||
static struct diff_tempfile *claim_diff_tempfile(void) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
|
||||
@@ -781,9 +821,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
diff_words_flush(ecbdata);
|
||||
len = sane_truncate_line(ecbdata, line, len);
|
||||
find_lno(line, ecbdata);
|
||||
emit_line(ecbdata->file,
|
||||
diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
|
||||
reset, line, len);
|
||||
emit_hunk_header(ecbdata, line, len);
|
||||
if (line[len-1] != '\n')
|
||||
putc('\n', ecbdata->file);
|
||||
return;
|
||||
|
||||
1
diff.h
1
diff.h
@@ -130,6 +130,7 @@ enum color_diff {
|
||||
DIFF_FILE_NEW = 5,
|
||||
DIFF_COMMIT = 6,
|
||||
DIFF_WHITESPACE = 7,
|
||||
DIFF_FUNCINFO = 8,
|
||||
};
|
||||
const char *diff_get_color(int diff_use_color, enum color_diff ix);
|
||||
#define diff_get_color_opt(o, ix) \
|
||||
|
||||
@@ -84,6 +84,8 @@ static void setup_git_env(void)
|
||||
git_graft_file = getenv(GRAFT_ENVIRONMENT);
|
||||
if (!git_graft_file)
|
||||
git_graft_file = git_pathdup("info/grafts");
|
||||
if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
|
||||
read_replace_refs = 0;
|
||||
}
|
||||
|
||||
int is_bare_repository(void)
|
||||
|
||||
15
git-am.sh
15
git-am.sh
@@ -205,7 +205,7 @@ check_patch_format () {
|
||||
# and see if it looks like that they all begin with the
|
||||
# header field names...
|
||||
sed -n -e '/^$/q' -e '/^[ ]/d' -e p "$1" |
|
||||
LC_ALL=C egrep -v '^[!-9;-~]+:' >/dev/null ||
|
||||
sane_egrep -v '^[!-9;-~]+:' >/dev/null ||
|
||||
patch_format=mbox
|
||||
fi
|
||||
} < "$1" || clean_abort
|
||||
@@ -561,7 +561,7 @@ do
|
||||
stop_here $this
|
||||
|
||||
# skip pine's internal folder data
|
||||
grep '^Author: Mail System Internal Data$' \
|
||||
sane_grep '^Author: Mail System Internal Data$' \
|
||||
<"$dotest"/info >/dev/null &&
|
||||
go_next && continue
|
||||
|
||||
@@ -577,11 +577,12 @@ do
|
||||
git cat-file commit "$commit" |
|
||||
sed -e '1,/^$/d' >"$dotest/msg-clean"
|
||||
else
|
||||
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
|
||||
case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
|
||||
|
||||
(printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") |
|
||||
git stripspace > "$dotest/msg-clean"
|
||||
{
|
||||
sed -n '/^Subject/ s/Subject: //p' "$dotest/info"
|
||||
echo
|
||||
cat "$dotest/msg"
|
||||
} |
|
||||
git stripspace > "$dotest/msg-clean"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -300,8 +300,7 @@ bisect_visualize() {
|
||||
esac
|
||||
fi
|
||||
|
||||
not=$(git for-each-ref --format='%(refname)' "refs/bisect/good-*")
|
||||
eval '"$@"' refs/bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
|
||||
eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
|
||||
}
|
||||
|
||||
bisect_reset() {
|
||||
@@ -393,7 +392,7 @@ bisect_run () {
|
||||
|
||||
cat "$GIT_DIR/BISECT_RUN"
|
||||
|
||||
if grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
|
||||
if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
|
||||
> /dev/null; then
|
||||
echo >&2 "bisect run cannot continue any more"
|
||||
exit $res
|
||||
@@ -405,7 +404,7 @@ bisect_run () {
|
||||
exit $res
|
||||
fi
|
||||
|
||||
if grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
|
||||
if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
|
||||
echo "bisect run success"
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
@@ -473,7 +473,7 @@ if [ "$filter_tag_name" ]; then
|
||||
git mktag) ||
|
||||
die "Could not create new tag object for $ref"
|
||||
if git cat-file tag "$ref" | \
|
||||
grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
|
||||
sane_grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
|
||||
then
|
||||
warn "gpg signature stripped from tag object $sha1t"
|
||||
fi
|
||||
|
||||
@@ -41,7 +41,7 @@ resolve_full_httpd () {
|
||||
case "$httpd" in
|
||||
*apache2*|*lighttpd*)
|
||||
# ensure that the apache2/lighttpd command ends with "-f"
|
||||
if ! echo "$httpd" | grep -- '-f *$' >/dev/null 2>&1
|
||||
if ! echo "$httpd" | sane_grep -- '-f *$' >/dev/null 2>&1
|
||||
then
|
||||
httpd="$httpd -f"
|
||||
fi
|
||||
@@ -73,6 +73,11 @@ resolve_full_httpd () {
|
||||
}
|
||||
|
||||
start_httpd () {
|
||||
if test -f "$fqgitdir/pid"; then
|
||||
say "Instance already running. Restarting..."
|
||||
stop_httpd
|
||||
fi
|
||||
|
||||
# here $httpd should have a meaningful value
|
||||
resolve_full_httpd
|
||||
|
||||
@@ -297,8 +302,8 @@ EOF
|
||||
|
||||
# check to see if Dennis Stosberg's mod_perl compatibility patch
|
||||
# (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied
|
||||
if test -f "$module_path/mod_perl.so" && grep 'MOD_PERL' \
|
||||
"$GIT_DIR/gitweb/gitweb.cgi" >/dev/null
|
||||
if test -f "$module_path/mod_perl.so" &&
|
||||
sane_grep 'MOD_PERL' "$GIT_DIR/gitweb/gitweb.cgi" >/dev/null
|
||||
then
|
||||
# favor mod_perl if available
|
||||
cat >> "$conf" <<EOF
|
||||
@@ -316,7 +321,7 @@ EOF
|
||||
# plain-old CGI
|
||||
resolve_full_httpd
|
||||
list_mods=$(echo "$full_httpd" | sed "s/-f$/-l/")
|
||||
$list_mods | grep 'mod_cgi\.c' >/dev/null 2>&1 || \
|
||||
$list_mods | sane_grep 'mod_cgi\.c' >/dev/null 2>&1 || \
|
||||
if test -f "$module_path/mod_cgi.so"
|
||||
then
|
||||
echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf"
|
||||
@@ -389,8 +394,15 @@ gitweb_css () {
|
||||
EOFGITWEB
|
||||
}
|
||||
|
||||
gitweb_js () {
|
||||
cat > "$1" <<\EOFGITWEB
|
||||
@@GITWEB_JS@@
|
||||
EOFGITWEB
|
||||
}
|
||||
|
||||
gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi"
|
||||
gitweb_css "$GIT_DIR/gitweb/gitweb.css"
|
||||
gitweb_js "$GIT_DIR/gitweb/gitweb.js"
|
||||
|
||||
case "$httpd" in
|
||||
*lighttpd*)
|
||||
|
||||
@@ -338,15 +338,14 @@ guess_merge_tool () {
|
||||
fi
|
||||
tools="$tools gvimdiff diffuse ecmerge p4merge araxis"
|
||||
fi
|
||||
if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then
|
||||
# $EDITOR is emacs so add emerge as a candidate
|
||||
tools="$tools emerge vimdiff"
|
||||
elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then
|
||||
# $EDITOR is vim so add vimdiff as a candidate
|
||||
case "${VISUAL:-$EDITOR}" in
|
||||
*vim*)
|
||||
tools="$tools vimdiff emerge"
|
||||
else
|
||||
;;
|
||||
*)
|
||||
tools="$tools emerge vimdiff"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
echo >&2 "merge tool candidates: $tools"
|
||||
|
||||
# Loop over each candidate and stop when a valid merge tool is found.
|
||||
|
||||
@@ -216,7 +216,7 @@ fi
|
||||
|
||||
merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
|
||||
test true = "$rebase" &&
|
||||
exec git-rebase $diffstat $strategy_args --onto $merge_head \
|
||||
exec git rebase $diffstat $strategy_args --onto $merge_head \
|
||||
${oldremoteref:-$merge_head}
|
||||
exec git-merge $diffstat $no_commit $squash $no_ff $ff_only $log_arg $strategy_args \
|
||||
"$merge_name" HEAD $merge_head $verbosity
|
||||
exec git merge $verbosity $diffstat $no_commit $squash $no_ff $ff_only $log_arg $strategy_args \
|
||||
-m "$merge_name" $merge_head
|
||||
|
||||
@@ -106,8 +106,8 @@ mark_action_done () {
|
||||
sed -e 1q < "$TODO" >> "$DONE"
|
||||
sed -e 1d < "$TODO" >> "$TODO".new
|
||||
mv -f "$TODO".new "$TODO"
|
||||
count=$(grep -c '^[^#]' < "$DONE")
|
||||
total=$(($count+$(grep -c '^[^#]' < "$TODO")))
|
||||
count=$(sane_grep -c '^[^#]' < "$DONE")
|
||||
total=$(($count+$(sane_grep -c '^[^#]' < "$TODO")))
|
||||
if test "$last_count" != "$count"
|
||||
then
|
||||
last_count=$count
|
||||
@@ -147,7 +147,7 @@ die_abort () {
|
||||
}
|
||||
|
||||
has_action () {
|
||||
grep '^[^#]' "$1" >/dev/null
|
||||
sane_grep '^[^#]' "$1" >/dev/null
|
||||
}
|
||||
|
||||
pick_one () {
|
||||
@@ -744,7 +744,7 @@ first and then run 'git rebase --continue' again."
|
||||
git rev-list $REVISIONS |
|
||||
while read rev
|
||||
do
|
||||
if test -f "$REWRITTEN"/$rev -a "$(grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
|
||||
if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
|
||||
then
|
||||
# Use -f2 because if rev-list is telling us this commit is
|
||||
# not worthwhile, we don't want to track its multiple heads,
|
||||
@@ -752,7 +752,7 @@ first and then run 'git rebase --continue' again."
|
||||
# be rebasing on top of it
|
||||
git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
|
||||
short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
|
||||
grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
|
||||
sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
|
||||
rm "$REWRITTEN"/$rev
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -467,7 +467,7 @@ orig_head=$branch
|
||||
mb=$(git merge-base "$onto" "$branch")
|
||||
if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
|
||||
# linear history?
|
||||
! (git rev-list --parents "$onto".."$branch" | grep " .* ") > /dev/null
|
||||
! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null
|
||||
then
|
||||
if test -z "$force_rebase"
|
||||
then
|
||||
|
||||
@@ -187,9 +187,11 @@ my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
|
||||
my ($validate, $confirm);
|
||||
my (@suppress_cc);
|
||||
|
||||
my $not_set_by_user = "true but not set by the user";
|
||||
|
||||
my %config_bool_settings = (
|
||||
"thread" => [\$thread, 1],
|
||||
"chainreplyto" => [\$chain_reply_to, 1],
|
||||
"chainreplyto" => [\$chain_reply_to, $not_set_by_user],
|
||||
"suppressfrom" => [\$suppress_from, undef],
|
||||
"signedoffbycc" => [\$signed_off_by_cc, undef],
|
||||
"signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated
|
||||
@@ -214,6 +216,19 @@ my %config_settings = (
|
||||
"from" => \$sender,
|
||||
);
|
||||
|
||||
# Help users prepare for 1.7.0
|
||||
sub chain_reply_to {
|
||||
if (defined $chain_reply_to &&
|
||||
$chain_reply_to eq $not_set_by_user) {
|
||||
print STDERR
|
||||
"In git 1.7.0, the default will be changed to --no-chain-reply-to\n" .
|
||||
"Set sendemail.chainreplyto configuration variable to true if\n" .
|
||||
"you want to keep --chain-reply-to as your default.\n";
|
||||
$chain_reply_to = 1;
|
||||
}
|
||||
return $chain_reply_to;
|
||||
}
|
||||
|
||||
# Handle Uncouth Termination
|
||||
sub signal_handler {
|
||||
|
||||
@@ -862,7 +877,9 @@ X-Mailer: git-send-email $gitversion
|
||||
|
||||
my @sendmail_parameters = ('-i', @recipients);
|
||||
my $raw_from = $sanitized_sender;
|
||||
$raw_from = $envelope_sender if (defined $envelope_sender);
|
||||
if (defined $envelope_sender && $envelope_sender ne "auto") {
|
||||
$raw_from = $envelope_sender;
|
||||
}
|
||||
$raw_from = extract_valid_address($raw_from);
|
||||
unshift (@sendmail_parameters,
|
||||
'-f', $raw_from) if(defined $envelope_sender);
|
||||
@@ -1157,7 +1174,7 @@ foreach my $t (@files) {
|
||||
|
||||
# set up for the next message
|
||||
if ($thread && $message_was_sent &&
|
||||
($chain_reply_to || !defined $reply_to || length($reply_to) == 0)) {
|
||||
(chain_reply_to() || !defined $reply_to || length($reply_to) == 0)) {
|
||||
$reply_to = $message_id;
|
||||
if (length $references > 0) {
|
||||
$references .= "\n $message_id";
|
||||
|
||||
@@ -107,6 +107,14 @@ git_editor() {
|
||||
eval "$GIT_EDITOR" '"$@"'
|
||||
}
|
||||
|
||||
sane_grep () {
|
||||
GREP_OPTIONS= LC_ALL=C grep "$@"
|
||||
}
|
||||
|
||||
sane_egrep () {
|
||||
GREP_OPTIONS= LC_ALL=C egrep "$@"
|
||||
}
|
||||
|
||||
is_bare_repository () {
|
||||
git rev-parse --is-bare-repository
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ resolve_relative_url ()
|
||||
#
|
||||
module_list()
|
||||
{
|
||||
git ls-files --error-unmatch --stage -- "$@" | grep '^160000 '
|
||||
git ls-files --error-unmatch --stage -- "$@" | sane_grep '^160000 '
|
||||
}
|
||||
|
||||
#
|
||||
@@ -572,7 +572,7 @@ cmd_summary() {
|
||||
cd_to_toplevel
|
||||
# Get modified modules cared by user
|
||||
modules=$(git $diff_cmd $cached --raw $head -- "$@" |
|
||||
egrep '^:([0-7]* )?160000' |
|
||||
sane_egrep '^:([0-7]* )?160000' |
|
||||
while read mod_src mod_dst sha1_src sha1_dst status name
|
||||
do
|
||||
# Always show modules deleted or type-changed (blob<->module)
|
||||
@@ -586,7 +586,7 @@ cmd_summary() {
|
||||
test -z "$modules" && return
|
||||
|
||||
git $diff_cmd $cached --raw $head -- $modules |
|
||||
egrep '^:([0-7]* )?160000' |
|
||||
sane_egrep '^:([0-7]* )?160000' |
|
||||
cut -c2- |
|
||||
while read mod_src mod_dst sha1_src sha1_dst status name
|
||||
do
|
||||
|
||||
3
git.c
3
git.c
@@ -89,6 +89,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
|
||||
*envchanged = 1;
|
||||
} else if (!strcmp(cmd, "--no-replace-objects")) {
|
||||
read_replace_refs = 0;
|
||||
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
|
||||
if (envchanged)
|
||||
*envchanged = 1;
|
||||
} else if (!strcmp(cmd, "--git-dir")) {
|
||||
if (*argc < 2) {
|
||||
fprintf(stderr, "No directory given for --git-dir.\n" );
|
||||
|
||||
@@ -92,6 +92,10 @@ You can specify the following configuration variables when building GIT:
|
||||
web browsers that support favicons (website icons) may display them
|
||||
in the browser's URL bar and next to site name in bookmarks). Relative
|
||||
to base URI of gitweb. [Default: git-favicon.png]
|
||||
* GITWEB_JS
|
||||
Points to the localtion where you put gitweb.js on your web server
|
||||
(or to be more generic URI of JavaScript code used by gitweb).
|
||||
Relative to base URI of gitweb. [Default: gitweb.js]
|
||||
* GITWEB_CONFIG
|
||||
This Perl file will be loaded using 'do' and can be used to override any
|
||||
of the options above as well as some other options -- see the "Runtime
|
||||
|
||||
@@ -79,6 +79,13 @@ div.page_footer_text {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div#generating_info {
|
||||
margin: 4px;
|
||||
font-size: smaller;
|
||||
text-align: center;
|
||||
color: #505050;
|
||||
}
|
||||
|
||||
div.page_body {
|
||||
padding: 8px;
|
||||
font-family: monospace;
|
||||
@@ -254,6 +261,11 @@ tr.no-previous td.linenr {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* for 'blame_incremental', during processing */
|
||||
tr.color1 { background-color: #f6fff6; }
|
||||
tr.color2 { background-color: #f6f6ff; }
|
||||
tr.color3 { background-color: #fff6f6; }
|
||||
|
||||
td {
|
||||
padding: 2px 5px;
|
||||
font-size: 100%;
|
||||
@@ -345,6 +357,17 @@ td.mode {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* progress of blame_interactive */
|
||||
div#progress_bar {
|
||||
height: 2px;
|
||||
margin-bottom: -2px;
|
||||
background-color: #d8d9d0;
|
||||
}
|
||||
div#progress_info {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* format of (optional) objects size in 'tree' view */
|
||||
td.size {
|
||||
font-family: monospace;
|
||||
|
||||
870
gitweb/gitweb.js
Normal file
870
gitweb/gitweb.js
Normal file
@@ -0,0 +1,870 @@
|
||||
// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com>
|
||||
// 2007, Petr Baudis <pasky@suse.cz>
|
||||
// 2008-2009, Jakub Narebski <jnareb@gmail.com>
|
||||
|
||||
/**
|
||||
* @fileOverview JavaScript code for gitweb (git web interface).
|
||||
* @license GPLv2 or later
|
||||
*/
|
||||
|
||||
/* ============================================================ */
|
||||
/* functions for generic gitweb actions and views */
|
||||
|
||||
/**
|
||||
* used to check if link has 'js' query parameter already (at end),
|
||||
* and other reasons to not add 'js=1' param at the end of link
|
||||
* @constant
|
||||
*/
|
||||
var jsExceptionsRe = /[;?]js=[01]$/;
|
||||
|
||||
/**
|
||||
* Add '?js=1' or ';js=1' to the end of every link in the document
|
||||
* that doesn't have 'js' query parameter set already.
|
||||
*
|
||||
* Links with 'js=1' lead to JavaScript version of given action, if it
|
||||
* exists (currently there is only 'blame_incremental' for 'blame')
|
||||
*
|
||||
* @globals jsExceptionsRe
|
||||
*/
|
||||
function fixLinks() {
|
||||
var allLinks = document.getElementsByTagName("a") || document.links;
|
||||
for (var i = 0, len = allLinks.length; i < len; i++) {
|
||||
var link = allLinks[i];
|
||||
if (!jsExceptionsRe.test(link)) { // =~ /[;?]js=[01]$/;
|
||||
link.href +=
|
||||
(link.href.indexOf('?') === -1 ? '?' : ';') + 'js=1';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
/*
|
||||
* This code uses DOM methods instead of (nonstandard) innerHTML
|
||||
* to modify page.
|
||||
*
|
||||
* innerHTML is non-standard IE extension, though supported by most
|
||||
* browsers; however Firefox up to version 1.5 didn't implement it in
|
||||
* a strict mode (application/xml+xhtml mimetype).
|
||||
*
|
||||
* Also my simple benchmarks show that using elem.firstChild.data =
|
||||
* 'content' is slightly faster than elem.innerHTML = 'content'. It
|
||||
* is however more fragile (text element fragment must exists), and
|
||||
* less feature-rich (we cannot add HTML).
|
||||
*
|
||||
* Note that DOM 2 HTML is preferred over generic DOM 2 Core; the
|
||||
* equivalent using DOM 2 Core is usually shown in comments.
|
||||
*/
|
||||
|
||||
|
||||
/* ============================================================ */
|
||||
/* generic utility functions */
|
||||
|
||||
|
||||
/**
|
||||
* pad number N with nonbreakable spaces on the left, to WIDTH characters
|
||||
* example: padLeftStr(12, 3, '\u00A0') == '\u00A012'
|
||||
* ('\u00A0' is nonbreakable space)
|
||||
*
|
||||
* @param {Number|String} input: number to pad
|
||||
* @param {Number} width: visible width of output
|
||||
* @param {String} str: string to prefix to string, e.g. '\u00A0'
|
||||
* @returns {String} INPUT prefixed with (WIDTH - INPUT.length) x STR
|
||||
*/
|
||||
function padLeftStr(input, width, str) {
|
||||
var prefix = '';
|
||||
|
||||
width -= input.toString().length;
|
||||
while (width > 0) {
|
||||
prefix += str;
|
||||
width--;
|
||||
}
|
||||
return prefix + input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad INPUT on the left to SIZE width, using given padding character CH,
|
||||
* for example padLeft('a', 3, '_') is '__a'.
|
||||
*
|
||||
* @param {String} input: input value converted to string.
|
||||
* @param {Number} width: desired length of output.
|
||||
* @param {String} ch: single character to prefix to string.
|
||||
*
|
||||
* @returns {String} Modified string, at least SIZE length.
|
||||
*/
|
||||
function padLeft(input, width, ch) {
|
||||
var s = input + "";
|
||||
while (s.length < width) {
|
||||
s = ch + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create XMLHttpRequest object in cross-browser way
|
||||
* @returns XMLHttpRequest object, or null
|
||||
*/
|
||||
function createRequestObject() {
|
||||
try {
|
||||
return new XMLHttpRequest();
|
||||
} catch (e) {}
|
||||
try {
|
||||
return window.createRequest();
|
||||
} catch (e) {}
|
||||
try {
|
||||
return new ActiveXObject("Msxml2.XMLHTTP");
|
||||
} catch (e) {}
|
||||
try {
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
} catch (e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================ */
|
||||
/* utility/helper functions (and variables) */
|
||||
|
||||
var xhr; // XMLHttpRequest object
|
||||
var projectUrl; // partial query + separator ('?' or ';')
|
||||
|
||||
// 'commits' is an associative map. It maps SHA1s to Commit objects.
|
||||
var commits = {};
|
||||
|
||||
/**
|
||||
* constructor for Commit objects, used in 'blame'
|
||||
* @class Represents a blamed commit
|
||||
* @param {String} sha1: SHA-1 identifier of a commit
|
||||
*/
|
||||
function Commit(sha1) {
|
||||
if (this instanceof Commit) {
|
||||
this.sha1 = sha1;
|
||||
this.nprevious = 0; /* number of 'previous', effective parents */
|
||||
} else {
|
||||
return new Commit(sha1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ............................................................ */
|
||||
/* progress info, timing, error reporting */
|
||||
|
||||
var blamedLines = 0;
|
||||
var totalLines = '???';
|
||||
var div_progress_bar;
|
||||
var div_progress_info;
|
||||
|
||||
/**
|
||||
* Detects how many lines does a blamed file have,
|
||||
* This information is used in progress info
|
||||
*
|
||||
* @returns {Number|String} Number of lines in file, or string '...'
|
||||
*/
|
||||
function countLines() {
|
||||
var table =
|
||||
document.getElementById('blame_table') ||
|
||||
document.getElementsByTagName('table')[0];
|
||||
|
||||
if (table) {
|
||||
return table.getElementsByTagName('tr').length - 1; // for header
|
||||
} else {
|
||||
return '...';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update progress info and length (width) of progress bar
|
||||
*
|
||||
* @globals div_progress_info, div_progress_bar, blamedLines, totalLines
|
||||
*/
|
||||
function updateProgressInfo() {
|
||||
if (!div_progress_info) {
|
||||
div_progress_info = document.getElementById('progress_info');
|
||||
}
|
||||
if (!div_progress_bar) {
|
||||
div_progress_bar = document.getElementById('progress_bar');
|
||||
}
|
||||
if (!div_progress_info && !div_progress_bar) {
|
||||
return;
|
||||
}
|
||||
|
||||
var percentage = Math.floor(100.0*blamedLines/totalLines);
|
||||
|
||||
if (div_progress_info) {
|
||||
div_progress_info.firstChild.data = blamedLines + ' / ' + totalLines +
|
||||
' (' + padLeftStr(percentage, 3, '\u00A0') + '%)';
|
||||
}
|
||||
|
||||
if (div_progress_bar) {
|
||||
//div_progress_bar.setAttribute('style', 'width: '+percentage+'%;');
|
||||
div_progress_bar.style.width = percentage + '%';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var t_interval_server = '';
|
||||
var cmds_server = '';
|
||||
var t0 = new Date();
|
||||
|
||||
/**
|
||||
* write how much it took to generate data, and to run script
|
||||
*
|
||||
* @globals t0, t_interval_server, cmds_server
|
||||
*/
|
||||
function writeTimeInterval() {
|
||||
var info_time = document.getElementById('generating_time');
|
||||
if (!info_time || !t_interval_server) {
|
||||
return;
|
||||
}
|
||||
var t1 = new Date();
|
||||
info_time.firstChild.data += ' + (' +
|
||||
t_interval_server + ' sec server blame_data / ' +
|
||||
(t1.getTime() - t0.getTime())/1000 + ' sec client JavaScript)';
|
||||
|
||||
var info_cmds = document.getElementById('generating_cmd');
|
||||
if (!info_time || !cmds_server) {
|
||||
return;
|
||||
}
|
||||
info_cmds.firstChild.data += ' + ' + cmds_server;
|
||||
}
|
||||
|
||||
/**
|
||||
* show an error message alert to user within page (in prohress info area)
|
||||
* @param {String} str: plain text error message (no HTML)
|
||||
*
|
||||
* @globals div_progress_info
|
||||
*/
|
||||
function errorInfo(str) {
|
||||
if (!div_progress_info) {
|
||||
div_progress_info = document.getElementById('progress_info');
|
||||
}
|
||||
if (div_progress_info) {
|
||||
div_progress_info.className = 'error';
|
||||
div_progress_info.firstChild.data = str;
|
||||
}
|
||||
}
|
||||
|
||||
/* ............................................................ */
|
||||
/* coloring rows during blame_data (git blame --incremental) run */
|
||||
|
||||
/**
|
||||
* used to extract N from 'colorN', where N is a number,
|
||||
* @constant
|
||||
*/
|
||||
var colorRe = /\bcolor([0-9]*)\b/;
|
||||
|
||||
/**
|
||||
* return N if <tr class="colorN">, otherwise return null
|
||||
* (some browsers require CSS class names to begin with letter)
|
||||
*
|
||||
* @param {HTMLElement} tr: table row element to check
|
||||
* @param {String} tr.className: 'class' attribute of tr element
|
||||
* @returns {Number|null} N if tr.className == 'colorN', otherwise null
|
||||
*
|
||||
* @globals colorRe
|
||||
*/
|
||||
function getColorNo(tr) {
|
||||
if (!tr) {
|
||||
return null;
|
||||
}
|
||||
var className = tr.className;
|
||||
if (className) {
|
||||
var match = colorRe.exec(className);
|
||||
if (match) {
|
||||
return parseInt(match[1], 10);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var colorsFreq = [0, 0, 0];
|
||||
/**
|
||||
* return one of given possible colors (curently least used one)
|
||||
* example: chooseColorNoFrom(2, 3) returns 2 or 3
|
||||
*
|
||||
* @param {Number[]} arguments: one or more numbers
|
||||
* assumes that 1 <= arguments[i] <= colorsFreq.length
|
||||
* @returns {Number} Least used color number from arguments
|
||||
* @globals colorsFreq
|
||||
*/
|
||||
function chooseColorNoFrom() {
|
||||
// choose the color which is least used
|
||||
var colorNo = arguments[0];
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
if (colorsFreq[arguments[i]-1] < colorsFreq[colorNo-1]) {
|
||||
colorNo = arguments[i];
|
||||
}
|
||||
}
|
||||
colorsFreq[colorNo-1]++;
|
||||
return colorNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* given two neigbour <tr> elements, find color which would be different
|
||||
* from color of both of neighbours; used to 3-color blame table
|
||||
*
|
||||
* @param {HTMLElement} tr_prev
|
||||
* @param {HTMLElement} tr_next
|
||||
* @returns {Number} color number N such that
|
||||
* colorN != tr_prev.className && colorN != tr_next.className
|
||||
*/
|
||||
function findColorNo(tr_prev, tr_next) {
|
||||
var color_prev = getColorNo(tr_prev);
|
||||
var color_next = getColorNo(tr_next);
|
||||
|
||||
|
||||
// neither of neighbours has color set
|
||||
// THEN we can use any of 3 possible colors
|
||||
if (!color_prev && !color_next) {
|
||||
return chooseColorNoFrom(1,2,3);
|
||||
}
|
||||
|
||||
// either both neighbours have the same color,
|
||||
// or only one of neighbours have color set
|
||||
// THEN we can use any color except given
|
||||
var color;
|
||||
if (color_prev === color_next) {
|
||||
color = color_prev; // = color_next;
|
||||
} else if (!color_prev) {
|
||||
color = color_next;
|
||||
} else if (!color_next) {
|
||||
color = color_prev;
|
||||
}
|
||||
if (color) {
|
||||
return chooseColorNoFrom((color % 3) + 1, ((color+1) % 3) + 1);
|
||||
}
|
||||
|
||||
// neighbours have different colors
|
||||
// THEN there is only one color left
|
||||
return (3 - ((color_prev + color_next) % 3));
|
||||
}
|
||||
|
||||
/* ............................................................ */
|
||||
/* coloring rows like 'blame' after 'blame_data' finishes */
|
||||
|
||||
/**
|
||||
* returns true if given row element (tr) is first in commit group
|
||||
* to be used only after 'blame_data' finishes (after processing)
|
||||
*
|
||||
* @param {HTMLElement} tr: table row
|
||||
* @returns {Boolean} true if TR is first in commit group
|
||||
*/
|
||||
function isStartOfGroup(tr) {
|
||||
return tr.firstChild.className === 'sha1';
|
||||
}
|
||||
|
||||
/**
|
||||
* change colors to use zebra coloring (2 colors) instead of 3 colors
|
||||
* concatenate neighbour commit groups belonging to the same commit
|
||||
*
|
||||
* @globals colorRe
|
||||
*/
|
||||
function fixColorsAndGroups() {
|
||||
var colorClasses = ['light', 'dark'];
|
||||
var linenum = 1;
|
||||
var tr, prev_group;
|
||||
var colorClass = 0;
|
||||
var table =
|
||||
document.getElementById('blame_table') ||
|
||||
document.getElementsByTagName('table')[0];
|
||||
|
||||
while ((tr = document.getElementById('l'+linenum))) {
|
||||
// index origin is 0, which is table header; start from 1
|
||||
//while ((tr = table.rows[linenum])) { // <- it is slower
|
||||
if (isStartOfGroup(tr, linenum, document)) {
|
||||
if (prev_group &&
|
||||
prev_group.firstChild.firstChild.href ===
|
||||
tr.firstChild.firstChild.href) {
|
||||
// we have to concatenate groups
|
||||
var prev_rows = prev_group.firstChild.rowSpan || 1;
|
||||
var curr_rows = tr.firstChild.rowSpan || 1;
|
||||
prev_group.firstChild.rowSpan = prev_rows + curr_rows;
|
||||
//tr.removeChild(tr.firstChild);
|
||||
tr.deleteCell(0); // DOM2 HTML way
|
||||
} else {
|
||||
colorClass = (colorClass + 1) % 2;
|
||||
prev_group = tr;
|
||||
}
|
||||
}
|
||||
var tr_class = tr.className;
|
||||
tr.className = tr_class.replace(colorRe, colorClasses[colorClass]);
|
||||
linenum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ............................................................ */
|
||||
/* time and data */
|
||||
|
||||
/**
|
||||
* used to extract hours and minutes from timezone info, e.g '-0900'
|
||||
* @constant
|
||||
*/
|
||||
var tzRe = /^([+-][0-9][0-9])([0-9][0-9])$/;
|
||||
|
||||
/**
|
||||
* return date in local time formatted in iso-8601 like format
|
||||
* 'yyyy-mm-dd HH:MM:SS +/-ZZZZ' e.g. '2005-08-07 21:49:46 +0200'
|
||||
*
|
||||
* @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC'
|
||||
* @param {String} timezoneInfo: numeric timezone '(+|-)HHMM'
|
||||
* @returns {String} date in local time in iso-8601 like format
|
||||
*
|
||||
* @globals tzRe
|
||||
*/
|
||||
function formatDateISOLocal(epoch, timezoneInfo) {
|
||||
var match = tzRe.exec(timezoneInfo);
|
||||
// date corrected by timezone
|
||||
var localDate = new Date(1000 * (epoch +
|
||||
(parseInt(match[1],10)*3600 + parseInt(match[2],10)*60)));
|
||||
var localDateStr = // e.g. '2005-08-07'
|
||||
localDate.getUTCFullYear() + '-' +
|
||||
padLeft(localDate.getUTCMonth()+1, 2, '0') + '-' +
|
||||
padLeft(localDate.getUTCDate(), 2, '0');
|
||||
var localTimeStr = // e.g. '21:49:46'
|
||||
padLeft(localDate.getUTCHours(), 2, '0') + ':' +
|
||||
padLeft(localDate.getUTCMinutes(), 2, '0') + ':' +
|
||||
padLeft(localDate.getUTCSeconds(), 2, '0');
|
||||
|
||||
return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo;
|
||||
}
|
||||
|
||||
/* ............................................................ */
|
||||
/* unquoting/unescaping filenames */
|
||||
|
||||
/**#@+
|
||||
* @constant
|
||||
*/
|
||||
var escCodeRe = /\\([^0-7]|[0-7]{1,3})/g;
|
||||
var octEscRe = /^[0-7]{1,3}$/;
|
||||
var maybeQuotedRe = /^\"(.*)\"$/;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* unquote maybe git-quoted filename
|
||||
* e.g. 'aa' -> 'aa', '"a\ta"' -> 'a a'
|
||||
*
|
||||
* @param {String} str: git-quoted string
|
||||
* @returns {String} Unquoted and unescaped string
|
||||
*
|
||||
* @globals escCodeRe, octEscRe, maybeQuotedRe
|
||||
*/
|
||||
function unquote(str) {
|
||||
function unq(seq) {
|
||||
var es = {
|
||||
// character escape codes, aka escape sequences (from C)
|
||||
// replacements are to some extent JavaScript specific
|
||||
t: "\t", // tab (HT, TAB)
|
||||
n: "\n", // newline (NL)
|
||||
r: "\r", // return (CR)
|
||||
f: "\f", // form feed (FF)
|
||||
b: "\b", // backspace (BS)
|
||||
a: "\x07", // alarm (bell) (BEL)
|
||||
e: "\x1B", // escape (ESC)
|
||||
v: "\v" // vertical tab (VT)
|
||||
};
|
||||
|
||||
if (seq.search(octEscRe) !== -1) {
|
||||
// octal char sequence
|
||||
return String.fromCharCode(parseInt(seq, 8));
|
||||
} else if (seq in es) {
|
||||
// C escape sequence, aka character escape code
|
||||
return es[seq];
|
||||
}
|
||||
// quoted ordinary character
|
||||
return seq;
|
||||
}
|
||||
|
||||
var match = str.match(maybeQuotedRe);
|
||||
if (match) {
|
||||
str = match[1];
|
||||
// perhaps str = eval('"'+str+'"'); would be enough?
|
||||
str = str.replace(escCodeRe,
|
||||
function (substr, p1, offset, s) { return unq(p1); });
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/* main part: parsing response */
|
||||
|
||||
/**
|
||||
* Function called for each blame entry, as soon as it finishes.
|
||||
* It updates page via DOM manipulation, adding sha1 info, etc.
|
||||
*
|
||||
* @param {Commit} commit: blamed commit
|
||||
* @param {Object} group: object representing group of lines,
|
||||
* which blame the same commit (blame entry)
|
||||
*
|
||||
* @globals blamedLines
|
||||
*/
|
||||
function handleLine(commit, group) {
|
||||
/*
|
||||
This is the structure of the HTML fragment we are working
|
||||
with:
|
||||
|
||||
<tr id="l123" class="">
|
||||
<td class="sha1" title=""><a href=""> </a></td>
|
||||
<td class="linenr"><a class="linenr" href="">123</a></td>
|
||||
<td class="pre"># times (my ext3 doesn't).</td>
|
||||
</tr>
|
||||
*/
|
||||
|
||||
var resline = group.resline;
|
||||
|
||||
// format date and time string only once per commit
|
||||
if (!commit.info) {
|
||||
/* e.g. 'Kay Sievers, 2005-08-07 21:49:46 +0200' */
|
||||
commit.info = commit.author + ', ' +
|
||||
formatDateISOLocal(commit.authorTime, commit.authorTimezone);
|
||||
}
|
||||
|
||||
// color depends on group of lines, not only on blamed commit
|
||||
var colorNo = findColorNo(
|
||||
document.getElementById('l'+(resline-1)),
|
||||
document.getElementById('l'+(resline+group.numlines))
|
||||
);
|
||||
|
||||
// loop over lines in commit group
|
||||
for (var i = 0; i < group.numlines; i++, resline++) {
|
||||
var tr = document.getElementById('l'+resline);
|
||||
if (!tr) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
<tr id="l123" class="">
|
||||
<td class="sha1" title=""><a href=""> </a></td>
|
||||
<td class="linenr"><a class="linenr" href="">123</a></td>
|
||||
<td class="pre"># times (my ext3 doesn't).</td>
|
||||
</tr>
|
||||
*/
|
||||
var td_sha1 = tr.firstChild;
|
||||
var a_sha1 = td_sha1.firstChild;
|
||||
var a_linenr = td_sha1.nextSibling.firstChild;
|
||||
|
||||
/* <tr id="l123" class=""> */
|
||||
var tr_class = '';
|
||||
if (colorNo !== null) {
|
||||
tr_class = 'color'+colorNo;
|
||||
}
|
||||
if (commit.boundary) {
|
||||
tr_class += ' boundary';
|
||||
}
|
||||
if (commit.nprevious === 0) {
|
||||
tr_class += ' no-previous';
|
||||
} else if (commit.nprevious > 1) {
|
||||
tr_class += ' multiple-previous';
|
||||
}
|
||||
tr.className = tr_class;
|
||||
|
||||
/* <td class="sha1" title="?" rowspan="?"><a href="?">?</a></td> */
|
||||
if (i === 0) {
|
||||
td_sha1.title = commit.info;
|
||||
td_sha1.rowSpan = group.numlines;
|
||||
|
||||
a_sha1.href = projectUrl + 'a=commit;h=' + commit.sha1;
|
||||
if (a_sha1.firstChild) {
|
||||
a_sha1.firstChild.data = commit.sha1.substr(0, 8);
|
||||
} else {
|
||||
a_sha1.appendChild(
|
||||
document.createTextNode(commit.sha1.substr(0, 8)));
|
||||
}
|
||||
if (group.numlines >= 2) {
|
||||
var fragment = document.createDocumentFragment();
|
||||
var br = document.createElement("br");
|
||||
var match = commit.author.match(/\b([A-Z])\B/g);
|
||||
if (match) {
|
||||
var text = document.createTextNode(
|
||||
match.join(''));
|
||||
}
|
||||
if (br && text) {
|
||||
var elem = fragment || td_sha1;
|
||||
elem.appendChild(br);
|
||||
elem.appendChild(text);
|
||||
if (fragment) {
|
||||
td_sha1.appendChild(fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//tr.removeChild(td_sha1); // DOM2 Core way
|
||||
tr.deleteCell(0); // DOM2 HTML way
|
||||
}
|
||||
|
||||
/* <td class="linenr"><a class="linenr" href="?">123</a></td> */
|
||||
var linenr_commit =
|
||||
('previous' in commit ? commit.previous : commit.sha1);
|
||||
var linenr_filename =
|
||||
('file_parent' in commit ? commit.file_parent : commit.filename);
|
||||
a_linenr.href = projectUrl + 'a=blame_incremental' +
|
||||
';hb=' + linenr_commit +
|
||||
';f=' + encodeURIComponent(linenr_filename) +
|
||||
'#l' + (group.srcline + i);
|
||||
|
||||
blamedLines++;
|
||||
|
||||
//updateProgressInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
var inProgress = false; // are we processing response
|
||||
|
||||
/**#@+
|
||||
* @constant
|
||||
*/
|
||||
var sha1Re = /^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/;
|
||||
var infoRe = /^([a-z-]+) ?(.*)/;
|
||||
var endRe = /^END ?([^ ]*) ?(.*)/;
|
||||
/**@-*/
|
||||
|
||||
var curCommit = new Commit();
|
||||
var curGroup = {};
|
||||
|
||||
var pollTimer = null;
|
||||
|
||||
/**
|
||||
* Parse output from 'git blame --incremental [...]', received via
|
||||
* XMLHttpRequest from server (blamedataUrl), and call handleLine
|
||||
* (which updates page) as soon as blame entry is completed.
|
||||
*
|
||||
* @param {String[]} lines: new complete lines from blamedata server
|
||||
*
|
||||
* @globals commits, curCommit, curGroup, t_interval_server, cmds_server
|
||||
* @globals sha1Re, infoRe, endRe
|
||||
*/
|
||||
function processBlameLines(lines) {
|
||||
var match;
|
||||
|
||||
for (var i = 0, len = lines.length; i < len; i++) {
|
||||
|
||||
if ((match = sha1Re.exec(lines[i]))) {
|
||||
var sha1 = match[1];
|
||||
var srcline = parseInt(match[2], 10);
|
||||
var resline = parseInt(match[3], 10);
|
||||
var numlines = parseInt(match[4], 10);
|
||||
|
||||
var c = commits[sha1];
|
||||
if (!c) {
|
||||
c = new Commit(sha1);
|
||||
commits[sha1] = c;
|
||||
}
|
||||
curCommit = c;
|
||||
|
||||
curGroup.srcline = srcline;
|
||||
curGroup.resline = resline;
|
||||
curGroup.numlines = numlines;
|
||||
|
||||
} else if ((match = infoRe.exec(lines[i]))) {
|
||||
var info = match[1];
|
||||
var data = match[2];
|
||||
switch (info) {
|
||||
case 'filename':
|
||||
curCommit.filename = unquote(data);
|
||||
// 'filename' information terminates the entry
|
||||
handleLine(curCommit, curGroup);
|
||||
updateProgressInfo();
|
||||
break;
|
||||
case 'author':
|
||||
curCommit.author = data;
|
||||
break;
|
||||
case 'author-time':
|
||||
curCommit.authorTime = parseInt(data, 10);
|
||||
break;
|
||||
case 'author-tz':
|
||||
curCommit.authorTimezone = data;
|
||||
break;
|
||||
case 'previous':
|
||||
curCommit.nprevious++;
|
||||
// store only first 'previous' header
|
||||
if (!'previous' in curCommit) {
|
||||
var parts = data.split(' ', 2);
|
||||
curCommit.previous = parts[0];
|
||||
curCommit.file_parent = unquote(parts[1]);
|
||||
}
|
||||
break;
|
||||
case 'boundary':
|
||||
curCommit.boundary = true;
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
} else if ((match = endRe.exec(lines[i]))) {
|
||||
t_interval_server = match[1];
|
||||
cmds_server = match[2];
|
||||
|
||||
} else if (lines[i] !== '') {
|
||||
// malformed line
|
||||
|
||||
} // end if (match)
|
||||
|
||||
} // end for (lines)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process new data and return pointer to end of processed part
|
||||
*
|
||||
* @param {String} unprocessed: new data (from nextReadPos)
|
||||
* @param {Number} nextReadPos: end of last processed data
|
||||
* @return {Number} end of processed data (new value for nextReadPos)
|
||||
*/
|
||||
function processData(unprocessed, nextReadPos) {
|
||||
var lastLineEnd = unprocessed.lastIndexOf('\n');
|
||||
if (lastLineEnd !== -1) {
|
||||
var lines = unprocessed.substring(0, lastLineEnd).split('\n');
|
||||
nextReadPos += lastLineEnd + 1 /* 1 == '\n'.length */;
|
||||
|
||||
processBlameLines(lines);
|
||||
} // end if
|
||||
|
||||
return nextReadPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle XMLHttpRequest errors
|
||||
*
|
||||
* @param {XMLHttpRequest} xhr: XMLHttpRequest object
|
||||
*
|
||||
* @globals pollTimer, commits, inProgress
|
||||
*/
|
||||
function handleError(xhr) {
|
||||
errorInfo('Server error: ' +
|
||||
xhr.status + ' - ' + (xhr.statusText || 'Error contacting server'));
|
||||
|
||||
clearInterval(pollTimer);
|
||||
commits = {}; // free memory
|
||||
|
||||
inProgress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after XMLHttpRequest finishes (loads)
|
||||
*
|
||||
* @param {XMLHttpRequest} xhr: XMLHttpRequest object (unused)
|
||||
*
|
||||
* @globals pollTimer, commits, inProgress
|
||||
*/
|
||||
function responseLoaded(xhr) {
|
||||
clearInterval(pollTimer);
|
||||
|
||||
fixColorsAndGroups();
|
||||
writeTimeInterval();
|
||||
commits = {}; // free memory
|
||||
|
||||
inProgress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* handler for XMLHttpRequest onreadystatechange event
|
||||
* @see startBlame
|
||||
*
|
||||
* @globals xhr, inProgress
|
||||
*/
|
||||
function handleResponse() {
|
||||
|
||||
/*
|
||||
* xhr.readyState
|
||||
*
|
||||
* Value Constant (W3C) Description
|
||||
* -------------------------------------------------------------------
|
||||
* 0 UNSENT open() has not been called yet.
|
||||
* 1 OPENED send() has not been called yet.
|
||||
* 2 HEADERS_RECEIVED send() has been called, and headers
|
||||
* and status are available.
|
||||
* 3 LOADING Downloading; responseText holds partial data.
|
||||
* 4 DONE The operation is complete.
|
||||
*/
|
||||
|
||||
if (xhr.readyState !== 4 && xhr.readyState !== 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the server returned error
|
||||
if (xhr.readyState === 3 && xhr.status !== 200) {
|
||||
return;
|
||||
}
|
||||
if (xhr.readyState === 4 && xhr.status !== 200) {
|
||||
handleError(xhr);
|
||||
return;
|
||||
}
|
||||
|
||||
// In konqueror xhr.responseText is sometimes null here...
|
||||
if (xhr.responseText === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// in case we were called before finished processing
|
||||
if (inProgress) {
|
||||
return;
|
||||
} else {
|
||||
inProgress = true;
|
||||
}
|
||||
|
||||
// extract new whole (complete) lines, and process them
|
||||
while (xhr.prevDataLength !== xhr.responseText.length) {
|
||||
if (xhr.readyState === 4 &&
|
||||
xhr.prevDataLength === xhr.responseText.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
xhr.prevDataLength = xhr.responseText.length;
|
||||
var unprocessed = xhr.responseText.substring(xhr.nextReadPos);
|
||||
xhr.nextReadPos = processData(unprocessed, xhr.nextReadPos);
|
||||
} // end while
|
||||
|
||||
// did we finish work?
|
||||
if (xhr.readyState === 4 &&
|
||||
xhr.prevDataLength === xhr.responseText.length) {
|
||||
responseLoaded(xhr);
|
||||
}
|
||||
|
||||
inProgress = false;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Incrementally update line data in blame_incremental view in gitweb.
|
||||
*
|
||||
* @param {String} blamedataUrl: URL to server script generating blame data.
|
||||
* @param {String} bUrl: partial URL to project, used to generate links.
|
||||
*
|
||||
* Called from 'blame_incremental' view after loading table with
|
||||
* file contents, a base for blame view.
|
||||
*
|
||||
* @globals xhr, t0, projectUrl, div_progress_bar, totalLines, pollTimer
|
||||
*/
|
||||
function startBlame(blamedataUrl, bUrl) {
|
||||
|
||||
xhr = createRequestObject();
|
||||
if (!xhr) {
|
||||
errorInfo('ERROR: XMLHttpRequest not supported');
|
||||
return;
|
||||
}
|
||||
|
||||
t0 = new Date();
|
||||
projectUrl = bUrl + (bUrl.indexOf('?') === -1 ? '?' : ';');
|
||||
if ((div_progress_bar = document.getElementById('progress_bar'))) {
|
||||
//div_progress_bar.setAttribute('style', 'width: 100%;');
|
||||
div_progress_bar.style.cssText = 'width: 100%;';
|
||||
}
|
||||
totalLines = countLines();
|
||||
updateProgressInfo();
|
||||
|
||||
/* add extra properties to xhr object to help processing response */
|
||||
xhr.prevDataLength = -1; // used to detect if we have new data
|
||||
xhr.nextReadPos = 0; // where unread part of response starts
|
||||
|
||||
xhr.onreadystatechange = handleResponse;
|
||||
//xhr.onreadystatechange = function () { handleResponse(xhr); };
|
||||
|
||||
xhr.open('GET', blamedataUrl);
|
||||
xhr.setRequestHeader('Accept', 'text/plain');
|
||||
xhr.send(null);
|
||||
|
||||
// not all browsers call onreadystatechange event on each server flush
|
||||
// poll response using timer every second to handle this issue
|
||||
pollTimer = setInterval(xhr.onreadystatechange, 1000);
|
||||
}
|
||||
|
||||
// end of gitweb.js
|
||||
@@ -18,6 +18,12 @@ use File::Find qw();
|
||||
use File::Basename qw(basename);
|
||||
binmode STDOUT, ':utf8';
|
||||
|
||||
our $t0;
|
||||
if (eval { require Time::HiRes; 1; }) {
|
||||
$t0 = [Time::HiRes::gettimeofday()];
|
||||
}
|
||||
our $number_of_git_cmds = 0;
|
||||
|
||||
BEGIN {
|
||||
CGI->compile() if $ENV{'MOD_PERL'};
|
||||
}
|
||||
@@ -90,6 +96,8 @@ our $stylesheet = undef;
|
||||
our $logo = "++GITWEB_LOGO++";
|
||||
# URI of GIT favicon, assumed to be image/png type
|
||||
our $favicon = "++GITWEB_FAVICON++";
|
||||
# URI of gitweb.js (JavaScript code for gitweb)
|
||||
our $javascript = "++GITWEB_JS++";
|
||||
|
||||
# URI and label (title) of GIT logo link
|
||||
#our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/";
|
||||
@@ -417,6 +425,20 @@ our %feature = (
|
||||
'sub' => \&feature_avatar,
|
||||
'override' => 0,
|
||||
'default' => ['']},
|
||||
|
||||
# Enable displaying how much time and how many git commands
|
||||
# it took to generate and display page. Disabled by default.
|
||||
# Project specific override is not supported.
|
||||
'timed' => {
|
||||
'override' => 0,
|
||||
'default' => [0]},
|
||||
|
||||
# Enable turning some links into links to actions which require
|
||||
# JavaScript to run (like 'blame_incremental'). Not enabled by
|
||||
# default. Project specific override is currently not supported.
|
||||
'javascript-actions' => {
|
||||
'override' => 0,
|
||||
'default' => [0]},
|
||||
);
|
||||
|
||||
sub gitweb_get_feature {
|
||||
@@ -531,6 +553,7 @@ if (-e $GITWEB_CONFIG) {
|
||||
|
||||
# version of the core git binary
|
||||
our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
|
||||
$number_of_git_cmds++;
|
||||
|
||||
$projects_list ||= $projectroot;
|
||||
|
||||
@@ -568,12 +591,16 @@ our @cgi_param_mapping = (
|
||||
snapshot_format => "sf",
|
||||
extra_options => "opt",
|
||||
search_use_regexp => "sr",
|
||||
# this must be last entry (for manipulation from JavaScript)
|
||||
javascript => "js"
|
||||
);
|
||||
our %cgi_param_mapping = @cgi_param_mapping;
|
||||
|
||||
# we will also need to know the possible actions, for validation
|
||||
our %actions = (
|
||||
"blame" => \&git_blame,
|
||||
"blame_incremental" => \&git_blame_incremental,
|
||||
"blame_data" => \&git_blame_data,
|
||||
"blobdiff" => \&git_blobdiff,
|
||||
"blobdiff_plain" => \&git_blobdiff_plain,
|
||||
"blob" => \&git_blob,
|
||||
@@ -2006,6 +2033,7 @@ sub get_feed_info {
|
||||
|
||||
# returns path to the core git executable and the --git-dir parameter as list
|
||||
sub git_cmd {
|
||||
$number_of_git_cmds++;
|
||||
return $GIT, '--git-dir='.$git_dir;
|
||||
}
|
||||
|
||||
@@ -2020,16 +2048,27 @@ sub quote_command {
|
||||
|
||||
# get HEAD ref of given project as hash
|
||||
sub git_get_head_hash {
|
||||
my $project = shift;
|
||||
return git_get_full_hash(shift, 'HEAD');
|
||||
}
|
||||
|
||||
sub git_get_full_hash {
|
||||
return git_get_hash(@_);
|
||||
}
|
||||
|
||||
sub git_get_short_hash {
|
||||
return git_get_hash(@_, '--short=7');
|
||||
}
|
||||
|
||||
sub git_get_hash {
|
||||
my ($project, $hash, @options) = @_;
|
||||
my $o_git_dir = $git_dir;
|
||||
my $retval = undef;
|
||||
$git_dir = "$projectroot/$project";
|
||||
if (open my $fd, "-|", git_cmd(), "rev-parse", "--verify", "HEAD") {
|
||||
my $head = <$fd>;
|
||||
if (open my $fd, '-|', git_cmd(), 'rev-parse',
|
||||
'--verify', '-q', @options, $hash) {
|
||||
$retval = <$fd>;
|
||||
chomp $retval if defined $retval;
|
||||
close $fd;
|
||||
if (defined $head && $head =~ /^([0-9a-fA-F]{40})$/) {
|
||||
$retval = $1;
|
||||
}
|
||||
}
|
||||
if (defined $o_git_dir) {
|
||||
$git_dir = $o_git_dir;
|
||||
@@ -3270,10 +3309,36 @@ sub git_footer_html {
|
||||
}
|
||||
print "</div>\n"; # class="page_footer"
|
||||
|
||||
if (defined $t0 && gitweb_check_feature('timed')) {
|
||||
print "<div id=\"generating_info\">\n";
|
||||
print 'This page took '.
|
||||
'<span id="generating_time" class="time_span">'.
|
||||
Time::HiRes::tv_interval($t0, [Time::HiRes::gettimeofday()]).
|
||||
' seconds </span>'.
|
||||
' and '.
|
||||
'<span id="generating_cmd">'.
|
||||
$number_of_git_cmds.
|
||||
'</span> git commands '.
|
||||
" to generate.\n";
|
||||
print "</div>\n"; # class="page_footer"
|
||||
}
|
||||
|
||||
if (-f $site_footer) {
|
||||
insert_file($site_footer);
|
||||
}
|
||||
|
||||
print qq!<script type="text/javascript" src="$javascript"></script>\n!;
|
||||
if ($action eq 'blame_incremental') {
|
||||
print qq!<script type="text/javascript">\n!.
|
||||
qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!.
|
||||
qq! "!. href() .qq!");\n!.
|
||||
qq!</script>\n!;
|
||||
} elsif (gitweb_check_feature('javascript-actions')) {
|
||||
print qq!<script type="text/javascript">\n!.
|
||||
qq!window.onload = fixLinks;\n!.
|
||||
qq!</script>\n!;
|
||||
}
|
||||
|
||||
print "</body>\n" .
|
||||
"</html>";
|
||||
}
|
||||
@@ -4870,7 +4935,13 @@ sub git_tag {
|
||||
git_footer_html();
|
||||
}
|
||||
|
||||
sub git_blame {
|
||||
sub git_blame_common {
|
||||
my $format = shift || 'porcelain';
|
||||
if ($format eq 'porcelain' && $cgi->param('js')) {
|
||||
$format = 'incremental';
|
||||
$action = 'blame_incremental'; # for page title etc
|
||||
}
|
||||
|
||||
# permissions
|
||||
gitweb_check_feature('blame')
|
||||
or die_error(403, "Blame view not allowed");
|
||||
@@ -4892,123 +4963,220 @@ sub git_blame {
|
||||
}
|
||||
}
|
||||
|
||||
# run git-blame --porcelain
|
||||
open my $fd, "-|", git_cmd(), "blame", '-p',
|
||||
$hash_base, '--', $file_name
|
||||
or die_error(500, "Open git-blame failed");
|
||||
my $fd;
|
||||
if ($format eq 'incremental') {
|
||||
# get file contents (as base)
|
||||
open $fd, "-|", git_cmd(), 'cat-file', 'blob', $hash
|
||||
or die_error(500, "Open git-cat-file failed");
|
||||
} elsif ($format eq 'data') {
|
||||
# run git-blame --incremental
|
||||
open $fd, "-|", git_cmd(), "blame", "--incremental",
|
||||
$hash_base, "--", $file_name
|
||||
or die_error(500, "Open git-blame --incremental failed");
|
||||
} else {
|
||||
# run git-blame --porcelain
|
||||
open $fd, "-|", git_cmd(), "blame", '-p',
|
||||
$hash_base, '--', $file_name
|
||||
or die_error(500, "Open git-blame --porcelain failed");
|
||||
}
|
||||
|
||||
# incremental blame data returns early
|
||||
if ($format eq 'data') {
|
||||
print $cgi->header(
|
||||
-type=>"text/plain", -charset => "utf-8",
|
||||
-status=> "200 OK");
|
||||
local $| = 1; # output autoflush
|
||||
print while <$fd>;
|
||||
close $fd
|
||||
or print "ERROR $!\n";
|
||||
|
||||
print 'END';
|
||||
if (defined $t0 && gitweb_check_feature('timed')) {
|
||||
print ' '.
|
||||
Time::HiRes::tv_interval($t0, [Time::HiRes::gettimeofday()]).
|
||||
' '.$number_of_git_cmds;
|
||||
}
|
||||
print "\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# page header
|
||||
git_header_html();
|
||||
my $formats_nav =
|
||||
$cgi->a({-href => href(action=>"blob", -replay=>1)},
|
||||
"blob") .
|
||||
" | ";
|
||||
if ($format eq 'incremental') {
|
||||
$formats_nav .=
|
||||
$cgi->a({-href => href(action=>"blame", javascript=>0, -replay=>1)},
|
||||
"blame") . " (non-incremental)";
|
||||
} else {
|
||||
$formats_nav .=
|
||||
$cgi->a({-href => href(action=>"blame_incremental", -replay=>1)},
|
||||
"blame") . " (incremental)";
|
||||
}
|
||||
$formats_nav .=
|
||||
" | " .
|
||||
$cgi->a({-href => href(action=>"history", -replay=>1)},
|
||||
"history") .
|
||||
" | " .
|
||||
$cgi->a({-href => href(action=>"blame", file_name=>$file_name)},
|
||||
$cgi->a({-href => href(action=>$action, file_name=>$file_name)},
|
||||
"HEAD");
|
||||
git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
|
||||
git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
|
||||
git_print_page_path($file_name, $ftype, $hash_base);
|
||||
|
||||
# page body
|
||||
if ($format eq 'incremental') {
|
||||
print "<noscript>\n<div class=\"error\"><center><b>\n".
|
||||
"This page requires JavaScript to run.\n Use ".
|
||||
$cgi->a({-href => href(action=>'blame',javascript=>0,-replay=>1)},
|
||||
'this page').
|
||||
" instead.\n".
|
||||
"</b></center></div>\n</noscript>\n";
|
||||
|
||||
print qq!<div id="progress_bar" style="width: 100%; background-color: yellow"></div>\n!;
|
||||
}
|
||||
|
||||
print qq!<div class="page_body">\n!;
|
||||
print qq!<div id="progress_info">... / ...</div>\n!
|
||||
if ($format eq 'incremental');
|
||||
print qq!<table id="blame_table" class="blame" width="100%">\n!.
|
||||
#qq!<col width="5.5em" /><col width="2.5em" /><col width="*" />\n!.
|
||||
qq!<thead>\n!.
|
||||
qq!<tr><th>Commit</th><th>Line</th><th>Data</th></tr>\n!.
|
||||
qq!</thead>\n!.
|
||||
qq!<tbody>\n!;
|
||||
|
||||
my @rev_color = qw(light dark);
|
||||
my $num_colors = scalar(@rev_color);
|
||||
my $current_color = 0;
|
||||
my %metainfo = ();
|
||||
|
||||
print <<HTML;
|
||||
<div class="page_body">
|
||||
<table class="blame">
|
||||
<tr><th>Commit</th><th>Line</th><th>Data</th></tr>
|
||||
HTML
|
||||
LINE:
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
# the header: <SHA-1> <src lineno> <dst lineno> [<lines in group>]
|
||||
# no <lines in group> for subsequent lines in group of lines
|
||||
my ($full_rev, $orig_lineno, $lineno, $group_size) =
|
||||
($line =~ /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/);
|
||||
if (!exists $metainfo{$full_rev}) {
|
||||
$metainfo{$full_rev} = { 'nprevious' => 0 };
|
||||
if ($format eq 'incremental') {
|
||||
my $color_class = $rev_color[$current_color];
|
||||
|
||||
#contents of a file
|
||||
my $linenr = 0;
|
||||
LINE:
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
$linenr++;
|
||||
|
||||
print qq!<tr id="l$linenr" class="$color_class">!.
|
||||
qq!<td class="sha1"><a href=""> </a></td>!.
|
||||
qq!<td class="linenr">!.
|
||||
qq!<a class="linenr" href="">$linenr</a></td>!;
|
||||
print qq!<td class="pre">! . esc_html($line) . "</td>\n";
|
||||
print qq!</tr>\n!;
|
||||
}
|
||||
my $meta = $metainfo{$full_rev};
|
||||
my $data;
|
||||
while ($data = <$fd>) {
|
||||
chomp $data;
|
||||
last if ($data =~ s/^\t//); # contents of line
|
||||
if ($data =~ /^(\S+)(?: (.*))?$/) {
|
||||
$meta->{$1} = $2 unless exists $meta->{$1};
|
||||
|
||||
} else { # porcelain, i.e. ordinary blame
|
||||
my %metainfo = (); # saves information about commits
|
||||
|
||||
# blame data
|
||||
LINE:
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
# the header: <SHA-1> <src lineno> <dst lineno> [<lines in group>]
|
||||
# no <lines in group> for subsequent lines in group of lines
|
||||
my ($full_rev, $orig_lineno, $lineno, $group_size) =
|
||||
($line =~ /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/);
|
||||
if (!exists $metainfo{$full_rev}) {
|
||||
$metainfo{$full_rev} = { 'nprevious' => 0 };
|
||||
}
|
||||
if ($data =~ /^previous /) {
|
||||
$meta->{'nprevious'}++;
|
||||
}
|
||||
}
|
||||
my $short_rev = substr($full_rev, 0, 8);
|
||||
my $author = $meta->{'author'};
|
||||
my %date =
|
||||
parse_date($meta->{'author-time'}, $meta->{'author-tz'});
|
||||
my $date = $date{'iso-tz'};
|
||||
if ($group_size) {
|
||||
$current_color = ($current_color + 1) % $num_colors;
|
||||
}
|
||||
my $tr_class = $rev_color[$current_color];
|
||||
$tr_class .= ' boundary' if (exists $meta->{'boundary'});
|
||||
$tr_class .= ' no-previous' if ($meta->{'nprevious'} == 0);
|
||||
$tr_class .= ' multiple-previous' if ($meta->{'nprevious'} > 1);
|
||||
print "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
|
||||
if ($group_size) {
|
||||
print "<td class=\"sha1\"";
|
||||
print " title=\"". esc_html($author) . ", $date\"";
|
||||
print " rowspan=\"$group_size\"" if ($group_size > 1);
|
||||
print ">";
|
||||
print $cgi->a({-href => href(action=>"commit",
|
||||
hash=>$full_rev,
|
||||
file_name=>$file_name)},
|
||||
esc_html($short_rev));
|
||||
if ($group_size >= 2) {
|
||||
my @author_initials = ($author =~ /\b([[:upper:]])\B/g);
|
||||
if (@author_initials) {
|
||||
print "<br />" .
|
||||
esc_html(join('', @author_initials));
|
||||
# or join('.', ...)
|
||||
my $meta = $metainfo{$full_rev};
|
||||
my $data;
|
||||
while ($data = <$fd>) {
|
||||
chomp $data;
|
||||
last if ($data =~ s/^\t//); # contents of line
|
||||
if ($data =~ /^(\S+)(?: (.*))?$/) {
|
||||
$meta->{$1} = $2 unless exists $meta->{$1};
|
||||
}
|
||||
if ($data =~ /^previous /) {
|
||||
$meta->{'nprevious'}++;
|
||||
}
|
||||
}
|
||||
print "</td>\n";
|
||||
}
|
||||
# 'previous' <sha1 of parent commit> <filename at commit>
|
||||
if (exists $meta->{'previous'} &&
|
||||
$meta->{'previous'} =~ /^([a-fA-F0-9]{40}) (.*)$/) {
|
||||
$meta->{'parent'} = $1;
|
||||
$meta->{'file_parent'} = unquote($2);
|
||||
}
|
||||
my $linenr_commit =
|
||||
exists($meta->{'parent'}) ?
|
||||
$meta->{'parent'} : $full_rev;
|
||||
my $linenr_filename =
|
||||
exists($meta->{'file_parent'}) ?
|
||||
$meta->{'file_parent'} : unquote($meta->{'filename'});
|
||||
my $blamed = href(action => 'blame',
|
||||
file_name => $linenr_filename,
|
||||
hash_base => $linenr_commit);
|
||||
print "<td class=\"linenr\">";
|
||||
print $cgi->a({ -href => "$blamed#l$orig_lineno",
|
||||
-class => "linenr" },
|
||||
esc_html($lineno));
|
||||
print "</td>";
|
||||
print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
|
||||
print "</tr>\n";
|
||||
my $short_rev = substr($full_rev, 0, 8);
|
||||
my $author = $meta->{'author'};
|
||||
my %date =
|
||||
parse_date($meta->{'author-time'}, $meta->{'author-tz'});
|
||||
my $date = $date{'iso-tz'};
|
||||
if ($group_size) {
|
||||
$current_color = ($current_color + 1) % $num_colors;
|
||||
}
|
||||
my $tr_class = $rev_color[$current_color];
|
||||
$tr_class .= ' boundary' if (exists $meta->{'boundary'});
|
||||
$tr_class .= ' no-previous' if ($meta->{'nprevious'} == 0);
|
||||
$tr_class .= ' multiple-previous' if ($meta->{'nprevious'} > 1);
|
||||
print "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
|
||||
if ($group_size) {
|
||||
print "<td class=\"sha1\"";
|
||||
print " title=\"". esc_html($author) . ", $date\"";
|
||||
print " rowspan=\"$group_size\"" if ($group_size > 1);
|
||||
print ">";
|
||||
print $cgi->a({-href => href(action=>"commit",
|
||||
hash=>$full_rev,
|
||||
file_name=>$file_name)},
|
||||
esc_html($short_rev));
|
||||
if ($group_size >= 2) {
|
||||
my @author_initials = ($author =~ /\b([[:upper:]])\B/g);
|
||||
if (@author_initials) {
|
||||
print "<br />" .
|
||||
esc_html(join('', @author_initials));
|
||||
# or join('.', ...)
|
||||
}
|
||||
}
|
||||
print "</td>\n";
|
||||
}
|
||||
# 'previous' <sha1 of parent commit> <filename at commit>
|
||||
if (exists $meta->{'previous'} &&
|
||||
$meta->{'previous'} =~ /^([a-fA-F0-9]{40}) (.*)$/) {
|
||||
$meta->{'parent'} = $1;
|
||||
$meta->{'file_parent'} = unquote($2);
|
||||
}
|
||||
my $linenr_commit =
|
||||
exists($meta->{'parent'}) ?
|
||||
$meta->{'parent'} : $full_rev;
|
||||
my $linenr_filename =
|
||||
exists($meta->{'file_parent'}) ?
|
||||
$meta->{'file_parent'} : unquote($meta->{'filename'});
|
||||
my $blamed = href(action => 'blame',
|
||||
file_name => $linenr_filename,
|
||||
hash_base => $linenr_commit);
|
||||
print "<td class=\"linenr\">";
|
||||
print $cgi->a({ -href => "$blamed#l$orig_lineno",
|
||||
-class => "linenr" },
|
||||
esc_html($lineno));
|
||||
print "</td>";
|
||||
print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
|
||||
print "</tr>\n";
|
||||
} # end while
|
||||
|
||||
}
|
||||
print "</table>\n";
|
||||
print "</div>";
|
||||
|
||||
# footer
|
||||
print "</tbody>\n".
|
||||
"</table>\n"; # class="blame"
|
||||
print "</div>\n"; # class="blame_body"
|
||||
close $fd
|
||||
or print "Reading blob failed\n";
|
||||
|
||||
# page footer
|
||||
git_footer_html();
|
||||
}
|
||||
|
||||
sub git_blame {
|
||||
git_blame_common();
|
||||
}
|
||||
|
||||
sub git_blame_incremental {
|
||||
git_blame_common('incremental');
|
||||
}
|
||||
|
||||
sub git_blame_data {
|
||||
git_blame_common('data');
|
||||
}
|
||||
|
||||
sub git_tags {
|
||||
my $head = git_get_head_hash($project);
|
||||
git_header_html();
|
||||
@@ -5285,6 +5453,43 @@ sub git_tree {
|
||||
git_footer_html();
|
||||
}
|
||||
|
||||
sub snapshot_name {
|
||||
my ($project, $hash) = @_;
|
||||
|
||||
# path/to/project.git -> project
|
||||
# path/to/project/.git -> project
|
||||
my $name = to_utf8($project);
|
||||
$name =~ s,([^/])/*\.git$,$1,;
|
||||
$name = basename($name);
|
||||
# sanitize name
|
||||
$name =~ s/[[:cntrl:]]/?/g;
|
||||
|
||||
my $ver = $hash;
|
||||
if ($hash =~ /^[0-9a-fA-F]+$/) {
|
||||
# shorten SHA-1 hash
|
||||
my $full_hash = git_get_full_hash($project, $hash);
|
||||
if ($full_hash =~ /^$hash/ && length($hash) > 7) {
|
||||
$ver = git_get_short_hash($project, $hash);
|
||||
}
|
||||
} elsif ($hash =~ m!^refs/tags/(.*)$!) {
|
||||
# tags don't need shortened SHA-1 hash
|
||||
$ver = $1;
|
||||
} else {
|
||||
# branches and other need shortened SHA-1 hash
|
||||
if ($hash =~ m!^refs/(?:heads|remotes)/(.*)$!) {
|
||||
$ver = $1;
|
||||
}
|
||||
$ver .= '-' . git_get_short_hash($project, $hash);
|
||||
}
|
||||
# in case of hierarchical branch names
|
||||
$ver =~ s!/!.!g;
|
||||
|
||||
# name = project-version_string
|
||||
$name = "$name-$ver";
|
||||
|
||||
return wantarray ? ($name, $name) : $name;
|
||||
}
|
||||
|
||||
sub git_snapshot {
|
||||
my $format = $input_params{'snapshot_format'};
|
||||
if (!@snapshot_fmts) {
|
||||
@@ -5302,28 +5507,27 @@ sub git_snapshot {
|
||||
die_error(403, "Unsupported snapshot format");
|
||||
}
|
||||
|
||||
if (!defined $hash) {
|
||||
$hash = git_get_head_hash($project);
|
||||
my $type = git_get_type("$hash^{}");
|
||||
if (!$type) {
|
||||
die_error(404, 'Object does not exist');
|
||||
} elsif ($type eq 'blob') {
|
||||
die_error(400, 'Object is not a tree-ish');
|
||||
}
|
||||
|
||||
my $name = $project;
|
||||
$name =~ s,([^/])/*\.git$,$1,;
|
||||
$name = basename($name);
|
||||
my $filename = to_utf8($name);
|
||||
$name =~ s/\047/\047\\\047\047/g;
|
||||
my $cmd;
|
||||
$filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}";
|
||||
$cmd = quote_command(
|
||||
my ($name, $prefix) = snapshot_name($project, $hash);
|
||||
my $filename = "$name$known_snapshot_formats{$format}{'suffix'}";
|
||||
my $cmd = quote_command(
|
||||
git_cmd(), 'archive',
|
||||
"--format=$known_snapshot_formats{$format}{'format'}",
|
||||
"--prefix=$name/", $hash);
|
||||
"--prefix=$prefix/", $hash);
|
||||
if (exists $known_snapshot_formats{$format}{'compressor'}) {
|
||||
$cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}});
|
||||
}
|
||||
|
||||
$filename =~ s/(["\\])/\\$1/g;
|
||||
print $cgi->header(
|
||||
-type => $known_snapshot_formats{$format}{'type'},
|
||||
-content_disposition => 'inline; filename="' . "$filename" . '"',
|
||||
-content_disposition => 'inline; filename="' . $filename . '"',
|
||||
-status => '200 OK');
|
||||
|
||||
open my $fd, "-|", $cmd
|
||||
|
||||
@@ -408,10 +408,10 @@ static void start_put(struct transfer_request *request)
|
||||
curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &request->buffer);
|
||||
#endif
|
||||
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
|
||||
|
||||
if (start_active_slot(slot)) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Fredrik Kuivinen.
|
||||
* The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
|
||||
*/
|
||||
#include "advice.h"
|
||||
#include "cache.h"
|
||||
#include "cache-tree.h"
|
||||
#include "commit.h"
|
||||
@@ -171,18 +172,6 @@ static int git_merge_trees(int index_only,
|
||||
int rc;
|
||||
struct tree_desc t[3];
|
||||
struct unpack_trees_options opts;
|
||||
static const struct unpack_trees_error_msgs msgs = {
|
||||
/* would_overwrite */
|
||||
"Your local changes to '%s' would be overwritten by merge. Aborting.",
|
||||
/* not_uptodate_file */
|
||||
"Your local changes to '%s' would be overwritten by merge. Aborting.",
|
||||
/* not_uptodate_dir */
|
||||
"Updating '%s' would lose untracked files in it. Aborting.",
|
||||
/* would_lose_untracked */
|
||||
"Untracked working tree file '%s' would be %s by merge. Aborting",
|
||||
/* bind_overlap -- will not happen here */
|
||||
NULL,
|
||||
};
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
if (index_only)
|
||||
@@ -194,7 +183,7 @@ static int git_merge_trees(int index_only,
|
||||
opts.fn = threeway_merge;
|
||||
opts.src_index = &the_index;
|
||||
opts.dst_index = &the_index;
|
||||
opts.msgs = msgs;
|
||||
opts.msgs = get_porcelain_error_msgs();
|
||||
|
||||
init_tree_desc_from_tree(t+0, common);
|
||||
init_tree_desc_from_tree(t+1, head);
|
||||
@@ -1182,6 +1171,28 @@ static int process_entry(struct merge_options *o,
|
||||
return clean_merge;
|
||||
}
|
||||
|
||||
struct unpack_trees_error_msgs get_porcelain_error_msgs(void)
|
||||
{
|
||||
struct unpack_trees_error_msgs msgs = {
|
||||
/* would_overwrite */
|
||||
"Your local changes to '%s' would be overwritten by merge. Aborting.",
|
||||
/* not_uptodate_file */
|
||||
"Your local changes to '%s' would be overwritten by merge. Aborting.",
|
||||
/* not_uptodate_dir */
|
||||
"Updating '%s' would lose untracked files in it. Aborting.",
|
||||
/* would_lose_untracked */
|
||||
"Untracked working tree file '%s' would be %s by merge. Aborting",
|
||||
/* bind_overlap -- will not happen here */
|
||||
NULL,
|
||||
};
|
||||
if (advice_commit_before_merge) {
|
||||
msgs.would_overwrite = msgs.not_uptodate_file =
|
||||
"Your local changes to '%s' would be overwritten by merge. Aborting.\n"
|
||||
"Please, commit your changes or stash them before you can merge.";
|
||||
}
|
||||
return msgs;
|
||||
}
|
||||
|
||||
int merge_trees(struct merge_options *o,
|
||||
struct tree *head,
|
||||
struct tree *merge,
|
||||
|
||||
@@ -17,6 +17,9 @@ struct merge_options {
|
||||
struct string_list current_directory_set;
|
||||
};
|
||||
|
||||
/* Return a list of user-friendly error messages to be used by merge */
|
||||
struct unpack_trees_error_msgs get_porcelain_error_msgs(void);
|
||||
|
||||
/* merge_trees() but with recursive ancestor consolidation */
|
||||
int merge_recursive(struct merge_options *o,
|
||||
struct commit *h1,
|
||||
|
||||
42
pretty.c
42
pretty.c
@@ -628,8 +628,8 @@ static void rewrap_message_tail(struct strbuf *sb,
|
||||
c->indent2 = new_indent2;
|
||||
}
|
||||
|
||||
static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
void *context)
|
||||
static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
|
||||
void *context)
|
||||
{
|
||||
struct format_commit_context *c = context;
|
||||
const struct commit *commit = c->commit;
|
||||
@@ -816,6 +816,44 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
return 0; /* unknown placeholder */
|
||||
}
|
||||
|
||||
static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
void *context)
|
||||
{
|
||||
int consumed;
|
||||
size_t orig_len;
|
||||
enum {
|
||||
NO_MAGIC,
|
||||
ADD_LF_BEFORE_NON_EMPTY,
|
||||
DEL_LF_BEFORE_EMPTY,
|
||||
} magic = NO_MAGIC;
|
||||
|
||||
switch (placeholder[0]) {
|
||||
case '-':
|
||||
magic = DEL_LF_BEFORE_EMPTY;
|
||||
break;
|
||||
case '+':
|
||||
magic = ADD_LF_BEFORE_NON_EMPTY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (magic != NO_MAGIC)
|
||||
placeholder++;
|
||||
|
||||
orig_len = sb->len;
|
||||
consumed = format_commit_one(sb, placeholder, context);
|
||||
if (magic == NO_MAGIC)
|
||||
return consumed;
|
||||
|
||||
if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) {
|
||||
while (sb->len && sb->buf[sb->len - 1] == '\n')
|
||||
strbuf_setlen(sb, sb->len - 1);
|
||||
} else if ((orig_len != sb->len) && magic == ADD_LF_BEFORE_NON_EMPTY) {
|
||||
strbuf_insert(sb, orig_len, "\n", 1);
|
||||
}
|
||||
return consumed + 1;
|
||||
}
|
||||
|
||||
void format_commit_message(const struct commit *commit,
|
||||
const char *format, struct strbuf *sb,
|
||||
const struct pretty_print_context *pretty_ctx)
|
||||
|
||||
7
refs.c
7
refs.c
@@ -286,6 +286,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
|
||||
}
|
||||
|
||||
struct warn_if_dangling_data {
|
||||
FILE *fp;
|
||||
const char *refname;
|
||||
const char *msg_fmt;
|
||||
};
|
||||
@@ -304,13 +305,13 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
|
||||
if (!resolves_to || strcmp(resolves_to, d->refname))
|
||||
return 0;
|
||||
|
||||
printf(d->msg_fmt, refname);
|
||||
fprintf(d->fp, d->msg_fmt, refname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void warn_dangling_symref(const char *msg_fmt, const char *refname)
|
||||
void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
|
||||
{
|
||||
struct warn_if_dangling_data data = { refname, msg_fmt };
|
||||
struct warn_if_dangling_data data = { fp, refname, msg_fmt };
|
||||
for_each_rawref(warn_if_dangling_symref, &data);
|
||||
}
|
||||
|
||||
|
||||
2
refs.h
2
refs.h
@@ -29,7 +29,7 @@ extern int for_each_replace_ref(each_ref_fn, void *);
|
||||
/* can be used to learn about broken ref and symref */
|
||||
extern int for_each_rawref(each_ref_fn, void *);
|
||||
|
||||
extern void warn_dangling_symref(const char *msg_fmt, const char *refname);
|
||||
extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
|
||||
|
||||
/*
|
||||
* Extra refs will be listed by for_each_ref() before any actual refs
|
||||
|
||||
@@ -307,7 +307,7 @@ static size_t rpc_out(void *ptr, size_t eltsize,
|
||||
rpc->len = avail;
|
||||
}
|
||||
|
||||
if (max < avail);
|
||||
if (max < avail)
|
||||
avail = max;
|
||||
memcpy(ptr, rpc->buf + rpc->pos, avail);
|
||||
rpc->pos += avail;
|
||||
@@ -356,8 +356,8 @@ static int post_rpc(struct rpc_state *rpc)
|
||||
slot = get_active_slot();
|
||||
slot->results = &results;
|
||||
|
||||
curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
|
||||
|
||||
|
||||
42
remote.c
42
remote.c
@@ -397,7 +397,8 @@ static int handle_config(const char *key, const char *value, void *cb)
|
||||
remote->mirror = git_config_bool(key, value);
|
||||
else if (!strcmp(subkey, ".skipdefaultupdate"))
|
||||
remote->skip_default_update = git_config_bool(key, value);
|
||||
|
||||
else if (!strcmp(subkey, ".skipfetchall"))
|
||||
remote->skip_default_update = git_config_bool(key, value);
|
||||
else if (!strcmp(subkey, ".url")) {
|
||||
const char *v;
|
||||
if (git_config_string(&v, key, value))
|
||||
@@ -1591,3 +1592,42 @@ struct ref *guess_remote_head(const struct ref *head,
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
struct stale_heads_info {
|
||||
struct remote *remote;
|
||||
struct string_list *ref_names;
|
||||
struct ref **stale_refs_tail;
|
||||
};
|
||||
|
||||
static int get_stale_heads_cb(const char *refname,
|
||||
const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct stale_heads_info *info = cb_data;
|
||||
struct refspec refspec;
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.dst = (char *)refname;
|
||||
if (!remote_find_tracking(info->remote, &refspec)) {
|
||||
if (!((flags & REF_ISSYMREF) ||
|
||||
string_list_has_string(info->ref_names, refspec.src))) {
|
||||
struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
|
||||
hashcpy(ref->new_sha1, sha1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map)
|
||||
{
|
||||
struct ref *ref, *stale_refs = NULL;
|
||||
struct string_list ref_names = { NULL, 0, 0, 0 };
|
||||
struct stale_heads_info info;
|
||||
info.remote = remote;
|
||||
info.ref_names = &ref_names;
|
||||
info.stale_refs_tail = &stale_refs;
|
||||
for (ref = fetch_map; ref; ref = ref->next)
|
||||
string_list_append(ref->name, &ref_names);
|
||||
sort_string_list(&ref_names);
|
||||
for_each_ref(get_stale_heads_cb, &info);
|
||||
string_list_clear(&ref_names, 0);
|
||||
return stale_refs;
|
||||
}
|
||||
|
||||
3
remote.h
3
remote.h
@@ -154,4 +154,7 @@ struct ref *guess_remote_head(const struct ref *head,
|
||||
const struct ref *refs,
|
||||
int all);
|
||||
|
||||
/* Return refs which no longer exist on remote */
|
||||
struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map);
|
||||
|
||||
#endif
|
||||
|
||||
106
revision.c
106
revision.c
@@ -953,21 +953,59 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_revisions_from_stdin(struct rev_info *revs)
|
||||
static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb, const char ***prune_data)
|
||||
{
|
||||
char line[1000];
|
||||
const char **prune = *prune_data;
|
||||
int prune_nr;
|
||||
int prune_alloc;
|
||||
|
||||
while (fgets(line, sizeof(line), stdin) != NULL) {
|
||||
int len = strlen(line);
|
||||
if (len && line[len - 1] == '\n')
|
||||
line[--len] = '\0';
|
||||
/* count existing ones */
|
||||
if (!prune)
|
||||
prune_nr = 0;
|
||||
else
|
||||
for (prune_nr = 0; prune[prune_nr]; prune_nr++)
|
||||
;
|
||||
prune_alloc = prune_nr; /* not really, but we do not know */
|
||||
|
||||
while (strbuf_getwholeline(sb, stdin, '\n') != EOF) {
|
||||
int len = sb->len;
|
||||
if (len && sb->buf[len - 1] == '\n')
|
||||
sb->buf[--len] = '\0';
|
||||
ALLOC_GROW(prune, prune_nr+1, prune_alloc);
|
||||
prune[prune_nr++] = xstrdup(sb->buf);
|
||||
}
|
||||
if (prune) {
|
||||
ALLOC_GROW(prune, prune_nr+1, prune_alloc);
|
||||
prune[prune_nr] = NULL;
|
||||
}
|
||||
*prune_data = prune;
|
||||
}
|
||||
|
||||
static void read_revisions_from_stdin(struct rev_info *revs, const char ***prune)
|
||||
{
|
||||
struct strbuf sb;
|
||||
int seen_dashdash = 0;
|
||||
|
||||
strbuf_init(&sb, 1000);
|
||||
while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) {
|
||||
int len = sb.len;
|
||||
if (len && sb.buf[len - 1] == '\n')
|
||||
sb.buf[--len] = '\0';
|
||||
if (!len)
|
||||
break;
|
||||
if (line[0] == '-')
|
||||
if (sb.buf[0] == '-') {
|
||||
if (len == 2 && sb.buf[1] == '-') {
|
||||
seen_dashdash = 1;
|
||||
break;
|
||||
}
|
||||
die("options not supported in --stdin mode");
|
||||
if (handle_revision_arg(line, revs, 0, 1))
|
||||
die("bad revision '%s'", line);
|
||||
}
|
||||
if (handle_revision_arg(sb.buf, revs, 0, 1))
|
||||
die("bad revision '%s'", sb.buf);
|
||||
}
|
||||
if (seen_dashdash)
|
||||
read_pathspec_from_stdin(revs, &sb, prune);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what)
|
||||
@@ -1229,6 +1267,34 @@ static int for_each_good_bisect_ref(each_ref_fn fn, void *cb_data)
|
||||
return for_each_ref_in("refs/bisect/good", fn, cb_data);
|
||||
}
|
||||
|
||||
static void append_prune_data(const char ***prune_data, const char **av)
|
||||
{
|
||||
const char **prune = *prune_data;
|
||||
int prune_nr;
|
||||
int prune_alloc;
|
||||
|
||||
if (!prune) {
|
||||
*prune_data = av;
|
||||
return;
|
||||
}
|
||||
|
||||
/* count existing ones */
|
||||
for (prune_nr = 0; prune[prune_nr]; prune_nr++)
|
||||
;
|
||||
prune_alloc = prune_nr; /* not really, but we do not know */
|
||||
|
||||
while (*av) {
|
||||
ALLOC_GROW(prune, prune_nr+1, prune_alloc);
|
||||
prune[prune_nr++] = *av;
|
||||
av++;
|
||||
}
|
||||
if (prune) {
|
||||
ALLOC_GROW(prune, prune_nr+1, prune_alloc);
|
||||
prune[prune_nr] = NULL;
|
||||
}
|
||||
*prune_data = prune;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse revision information, filling in the "rev_info" structure,
|
||||
* and removing the used arguments from the argument list.
|
||||
@@ -1238,7 +1304,8 @@ static int for_each_good_bisect_ref(each_ref_fn fn, void *cb_data)
|
||||
*/
|
||||
int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def)
|
||||
{
|
||||
int i, flags, left, seen_dashdash;
|
||||
int i, flags, left, seen_dashdash, read_from_stdin;
|
||||
const char **prune_data = NULL;
|
||||
|
||||
/* First, search for "--" */
|
||||
seen_dashdash = 0;
|
||||
@@ -1249,13 +1316,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
argv[i] = NULL;
|
||||
argc = i;
|
||||
if (argv[i + 1])
|
||||
revs->prune_data = get_pathspec(revs->prefix, argv + i + 1);
|
||||
prune_data = argv + i + 1;
|
||||
seen_dashdash = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Second, deal with arguments and options */
|
||||
flags = 0;
|
||||
read_from_stdin = 0;
|
||||
for (left = i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (*arg == '-') {
|
||||
@@ -1300,6 +1368,16 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
revs->no_walk = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--stdin")) {
|
||||
if (revs->disable_stdin) {
|
||||
argv[left++] = arg;
|
||||
continue;
|
||||
}
|
||||
if (read_from_stdin++)
|
||||
die("--stdin given twice?");
|
||||
read_revisions_from_stdin(revs, &prune_data);
|
||||
continue;
|
||||
}
|
||||
|
||||
opts = handle_revision_opt(revs, argc - i, argv + i, &left, argv);
|
||||
if (opts > 0) {
|
||||
@@ -1325,12 +1403,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
for (j = i; j < argc; j++)
|
||||
verify_filename(revs->prefix, argv[j]);
|
||||
|
||||
revs->prune_data = get_pathspec(revs->prefix,
|
||||
argv + i);
|
||||
append_prune_data(&prune_data, argv + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prune_data)
|
||||
revs->prune_data = get_pathspec(revs->prefix, prune_data);
|
||||
|
||||
if (revs->def == NULL)
|
||||
revs->def = def;
|
||||
if (revs->show_merge)
|
||||
|
||||
@@ -84,6 +84,8 @@ struct rev_info {
|
||||
use_terminator:1,
|
||||
missing_newline:1,
|
||||
date_mode_explicit:1;
|
||||
unsigned int disable_stdin:1;
|
||||
|
||||
enum date_mode date_mode;
|
||||
|
||||
unsigned int abbrev;
|
||||
@@ -129,8 +131,6 @@ struct rev_info {
|
||||
#define REV_TREE_DIFFERENT 3 /* Mixed changes */
|
||||
|
||||
/* revision.c */
|
||||
void read_revisions_from_stdin(struct rev_info *revs);
|
||||
|
||||
typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *);
|
||||
extern volatile show_early_output_fn_t show_early_output;
|
||||
|
||||
|
||||
13
t/README
13
t/README
@@ -75,6 +75,19 @@ appropriately before running "make".
|
||||
As the names depend on the tests' file names, it is safe to
|
||||
run the tests with this option in parallel.
|
||||
|
||||
You can also set the GIT_TEST_INSTALLED environment variable to
|
||||
the bindir of an existing git installation to test that installation.
|
||||
You still need to have built this git sandbox, from which various
|
||||
test-* support programs, templates, and perl libraries are used.
|
||||
If your installed git is incomplete, it will silently test parts of
|
||||
your built version instead.
|
||||
|
||||
When using GIT_TEST_INSTALLED, you can also set GIT_TEST_EXEC_PATH to
|
||||
override the location of the dashed-form subcommands (what
|
||||
GIT_EXEC_PATH would be used for during normal operation).
|
||||
GIT_TEST_EXEC_PATH defaults to `$GIT_TEST_INSTALLED/git --exec-path`.
|
||||
|
||||
|
||||
Skipping Tests
|
||||
--------------
|
||||
|
||||
|
||||
@@ -52,10 +52,24 @@ gitweb_run () {
|
||||
rm -f gitweb.log &&
|
||||
perl -- "$SCRIPT_NAME" \
|
||||
>gitweb.output 2>gitweb.log &&
|
||||
perl -w -e '
|
||||
open O, ">gitweb.headers";
|
||||
while (<>) {
|
||||
print O;
|
||||
last if (/^\r$/ || /^$/);
|
||||
}
|
||||
open O, ">gitweb.body";
|
||||
while (<>) {
|
||||
print O;
|
||||
}
|
||||
close O;
|
||||
' gitweb.output &&
|
||||
if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi
|
||||
|
||||
# gitweb.log is left for debugging
|
||||
# gitweb.output is used to parse http output
|
||||
# gitweb.output is used to parse HTTP output
|
||||
# gitweb.headers contains only HTTP headers
|
||||
# gitweb.body contains body of message, without headers
|
||||
}
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
@@ -47,7 +47,8 @@ test_expect_success 'tree' '
|
||||
'
|
||||
|
||||
test_expect_success 'git diff-index -p HEAD' '
|
||||
tree=$(git write-tree)
|
||||
test_tick &&
|
||||
tree=$(git write-tree) &&
|
||||
commit=$(echo "Initial commit" | git commit-tree $tree) &&
|
||||
git update-ref HEAD $commit &&
|
||||
git diff-index -p HEAD > diff.output &&
|
||||
@@ -113,12 +114,14 @@ test_expect_success 'git branch' '
|
||||
test_expect_success 'git resolve now fails' '
|
||||
git checkout mybranch &&
|
||||
echo "Work, work, work" >>hello &&
|
||||
test_tick &&
|
||||
git commit -m "Some work." -i hello &&
|
||||
|
||||
git checkout master &&
|
||||
|
||||
echo "Play, play, play" >>hello &&
|
||||
echo "Lots of fun" >>example &&
|
||||
test_tick &&
|
||||
git commit -m "Some fun." -i hello example &&
|
||||
|
||||
test_must_fail git merge -m "Merge work in mybranch" mybranch
|
||||
@@ -141,6 +144,7 @@ cat > show-branch.expect << EOF
|
||||
EOF
|
||||
|
||||
test_expect_success 'git show-branch' '
|
||||
test_tick &&
|
||||
git commit -m "Merge work in mybranch" -i hello &&
|
||||
git show-branch --topo-order --more=1 master mybranch \
|
||||
> show-branch.output &&
|
||||
@@ -201,9 +205,9 @@ cat > show-branch4.expect << EOF
|
||||
* [master] Some fun.
|
||||
! [mybranch] Some work.
|
||||
--
|
||||
+ [mybranch] Some work.
|
||||
* [master] Some fun.
|
||||
*+ [mybranch^] Initial commit
|
||||
+ [mybranch] Some work.
|
||||
*+ [master^] Initial commit
|
||||
EOF
|
||||
|
||||
test_expect_success 'git show-branch (part 4)' '
|
||||
|
||||
@@ -8,7 +8,7 @@ test_cd_to_toplevel () {
|
||||
test_expect_success $3 "$2" '
|
||||
(
|
||||
cd '"'$1'"' &&
|
||||
. git-sh-setup &&
|
||||
. "$(git --exec-path)"/git-sh-setup &&
|
||||
cd_to_toplevel &&
|
||||
[ "$(pwd -P)" = "$TOPLEVEL" ]
|
||||
)
|
||||
|
||||
@@ -32,14 +32,14 @@ export GIT_AUTHOR_EMAIL
|
||||
test_expect_success 'setup for merge-preserving rebase' \
|
||||
'echo First > A &&
|
||||
git add A &&
|
||||
git-commit -m "Add A1" &&
|
||||
git commit -m "Add A1" &&
|
||||
git checkout -b topic &&
|
||||
echo Second > B &&
|
||||
git add B &&
|
||||
git-commit -m "Add B1" &&
|
||||
git commit -m "Add B1" &&
|
||||
git checkout -f master &&
|
||||
echo Third >> A &&
|
||||
git-commit -a -m "Modify A2" &&
|
||||
git commit -a -m "Modify A2" &&
|
||||
|
||||
git clone ./. clone1 &&
|
||||
cd clone1 &&
|
||||
|
||||
@@ -549,9 +549,12 @@ test_expect_success 'options no longer allowed for format-patch' '
|
||||
test_cmp expect.check output'
|
||||
|
||||
test_expect_success 'format-patch --numstat should produce a patch' '
|
||||
git format-patch --numstat --stdout master..side |
|
||||
grep "^diff --git a/" |
|
||||
wc -l |
|
||||
xargs test 6 = '
|
||||
git format-patch --numstat --stdout master..side > output &&
|
||||
test 6 = $(grep "^diff --git a/" output | wc -l)'
|
||||
|
||||
test_expect_success 'format-patch -- <path>' '
|
||||
git format-patch master..side -- file 2>error &&
|
||||
! grep "Use .--" error
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -8,6 +8,7 @@ test_expect_success setup '
|
||||
|
||||
git config diff.color.old red
|
||||
git config diff.color.new green
|
||||
git config diff.color.func magenta
|
||||
|
||||
'
|
||||
|
||||
@@ -16,6 +17,7 @@ decrypt_color () {
|
||||
-e 's/.\[1m/<WHITE>/g' \
|
||||
-e 's/.\[31m/<RED>/g' \
|
||||
-e 's/.\[32m/<GREEN>/g' \
|
||||
-e 's/.\[35m/<MAGENTA>/g' \
|
||||
-e 's/.\[36m/<BROWN>/g' \
|
||||
-e 's/.\[m/<RESET>/g'
|
||||
}
|
||||
@@ -49,7 +51,7 @@ cat > expect <<\EOF
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
|
||||
<RESET>
|
||||
|
||||
a = b + c<RESET>
|
||||
|
||||
<GREEN>aa = a<RESET>
|
||||
@@ -70,7 +72,7 @@ cat > expect <<\EOF
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1 +1 @@<RESET>
|
||||
<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
|
||||
<BROWN>@@ -3,0 +4,4 @@ a = b + c<RESET>
|
||||
<BROWN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
|
||||
|
||||
<GREEN>aa = a<RESET>
|
||||
|
||||
@@ -90,7 +92,7 @@ cat > expect <<\EOF
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
h(4),<GREEN>hh<RESET>[44]
|
||||
<RESET>
|
||||
|
||||
a = b + c<RESET>
|
||||
|
||||
<GREEN>aa = a<RESET>
|
||||
@@ -126,7 +128,7 @@ cat > expect <<\EOF
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
h(4)<GREEN>,hh[44]<RESET>
|
||||
<RESET>
|
||||
|
||||
a = b + c<RESET>
|
||||
|
||||
<GREEN>aa = a<RESET>
|
||||
@@ -168,7 +170,7 @@ cat > expect <<\EOF
|
||||
<WHITE>+++ b/post<RESET>
|
||||
<BROWN>@@ -1,3 +1,7 @@<RESET>
|
||||
h(4),<GREEN>hh[44<RESET>]
|
||||
<RESET>
|
||||
|
||||
a = b + c<RESET>
|
||||
|
||||
<GREEN>aa = a<RESET>
|
||||
|
||||
@@ -136,37 +136,37 @@ void print_int(int num) {
|
||||
EOF
|
||||
|
||||
test_expect_success 'file creation' '
|
||||
git-apply patch1.patch
|
||||
git apply patch1.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch2 fails (retab)' '
|
||||
test_must_fail git-apply patch2.patch
|
||||
test_must_fail git apply patch2.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch2 applies with --ignore-whitespace' '
|
||||
git-apply --ignore-whitespace patch2.patch
|
||||
git apply --ignore-whitespace patch2.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch2 reverse applies with --ignore-space-change' '
|
||||
git-apply -R --ignore-space-change patch2.patch
|
||||
git apply -R --ignore-space-change patch2.patch
|
||||
'
|
||||
|
||||
git config apply.ignorewhitespace change
|
||||
|
||||
test_expect_success 'patch2 applies (apply.ignorewhitespace = change)' '
|
||||
git-apply patch2.patch
|
||||
git apply patch2.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch3 fails (missing string at EOL)' '
|
||||
test_must_fail git-apply patch3.patch
|
||||
test_must_fail git apply patch3.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch4 fails (missing EOL at EOF)' '
|
||||
test_must_fail git-apply patch4.patch
|
||||
test_must_fail git apply patch4.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch5 applies (leading whitespace)' '
|
||||
git-apply patch5.patch
|
||||
git apply patch5.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patches do not mangle whitespace' '
|
||||
@@ -175,11 +175,11 @@ test_expect_success 'patches do not mangle whitespace' '
|
||||
|
||||
test_expect_success 're-create file (with --ignore-whitespace)' '
|
||||
rm -f main.c &&
|
||||
git-apply patch1.patch
|
||||
git apply patch1.patch
|
||||
'
|
||||
|
||||
test_expect_success 'patch5 fails (--no-ignore-whitespace)' '
|
||||
test_must_fail git-apply --no-ignore-whitespace patch5.patch
|
||||
test_must_fail git apply --no-ignore-whitespace patch5.patch
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -57,6 +57,23 @@ test_expect_success 'apply --directory (new file)' '
|
||||
test content = $(cat some/sub/dir/newfile)
|
||||
'
|
||||
|
||||
cat > patch << EOF
|
||||
diff --git a/c/newfile2 b/c/newfile2
|
||||
new file mode 100644
|
||||
index 0000000..d95f3ad
|
||||
--- /dev/null
|
||||
+++ b/c/newfile2
|
||||
@@ -0,0 +1 @@
|
||||
+content
|
||||
EOF
|
||||
|
||||
test_expect_success 'apply --directory -p (new file)' '
|
||||
git reset --hard initial &&
|
||||
git apply -p2 --directory=some/sub/dir/ --index patch &&
|
||||
test content = $(git show :some/sub/dir/newfile2) &&
|
||||
test content = $(cat some/sub/dir/newfile2)
|
||||
'
|
||||
|
||||
cat > patch << EOF
|
||||
diff --git a/delfile b/delfile
|
||||
deleted file mode 100644
|
||||
|
||||
@@ -52,4 +52,32 @@ GIT_DIR=non-existing git shortlog -w < log > out
|
||||
|
||||
test_expect_success 'shortlog from non-git directory' 'test_cmp expect out'
|
||||
|
||||
iconvfromutf8toiso88591() {
|
||||
printf "%s" "$*" | iconv -f UTF-8 -t ISO-8859-1
|
||||
}
|
||||
|
||||
DSCHO="Jöhännës \"Dschö\" Schindëlin"
|
||||
DSCHOE="$DSCHO <Johannes.Schindelin@gmx.de>"
|
||||
MSG1="set a1 to 2 and some non-ASCII chars: Äßø"
|
||||
MSG2="set a1 to 3 and some non-ASCII chars: áæï"
|
||||
cat > expect << EOF
|
||||
$DSCHO (2):
|
||||
$MSG1
|
||||
$MSG2
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_success 'shortlog encoding' '
|
||||
git reset --hard "$commit" &&
|
||||
git config --unset i18n.commitencoding &&
|
||||
echo 2 > a1 &&
|
||||
git commit --quiet -m "$MSG1" --author="$DSCHOE" a1 &&
|
||||
git config i18n.commitencoding "ISO-8859-1" &&
|
||||
echo 3 > a1 &&
|
||||
git commit --quiet -m "$(iconvfromutf8toiso88591 "$MSG2")" \
|
||||
--author="$(iconvfromutf8toiso88591 "$DSCHOE")" a1 &&
|
||||
git config --unset i18n.commitencoding &&
|
||||
git shortlog HEAD~2.. > out &&
|
||||
test_cmp expect out'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -365,6 +365,17 @@ test_expect_success 'update with arguments' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'update --prune' '
|
||||
|
||||
(cd one &&
|
||||
git branch -m side2 side3) &&
|
||||
(cd test &&
|
||||
git remote update --prune &&
|
||||
(cd ../one && git branch -m side3 side2)
|
||||
git rev-parse refs/remotes/origin/side3 &&
|
||||
test_must_fail git rev-parse refs/remotes/origin/side2)
|
||||
'
|
||||
|
||||
cat > one/expect << EOF
|
||||
apis/master
|
||||
apis/side
|
||||
|
||||
@@ -51,7 +51,7 @@ test_expect_success 'nonexistant group produces error' '
|
||||
! repo_fetched two
|
||||
'
|
||||
|
||||
test_expect_success 'updating group updates all members' '
|
||||
test_expect_success 'updating group updates all members (remote update)' '
|
||||
mark group-all &&
|
||||
update_repos &&
|
||||
git config --add remotes.all one &&
|
||||
@@ -61,7 +61,15 @@ test_expect_success 'updating group updates all members' '
|
||||
repo_fetched two
|
||||
'
|
||||
|
||||
test_expect_success 'updating group does not update non-members' '
|
||||
test_expect_success 'updating group updates all members (fetch)' '
|
||||
mark fetch-group-all &&
|
||||
update_repos &&
|
||||
git fetch all &&
|
||||
repo_fetched one &&
|
||||
repo_fetched two
|
||||
'
|
||||
|
||||
test_expect_success 'updating group does not update non-members (remote update)' '
|
||||
mark group-some &&
|
||||
update_repos &&
|
||||
git config --add remotes.some one &&
|
||||
@@ -70,6 +78,15 @@ test_expect_success 'updating group does not update non-members' '
|
||||
! repo_fetched two
|
||||
'
|
||||
|
||||
test_expect_success 'updating group does not update non-members (fetch)' '
|
||||
mark fetch-group-some &&
|
||||
update_repos &&
|
||||
git config --add remotes.some one &&
|
||||
git remote update some &&
|
||||
repo_fetched one &&
|
||||
! repo_fetched two
|
||||
'
|
||||
|
||||
test_expect_success 'updating remote name updates that remote' '
|
||||
mark remote-name &&
|
||||
update_repos &&
|
||||
|
||||
154
t/t5514-fetch-multiple.sh
Executable file
154
t/t5514-fetch-multiple.sh
Executable file
@@ -0,0 +1,154 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='fetch --all works correctly'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
setup_repository () {
|
||||
mkdir "$1" && (
|
||||
cd "$1" &&
|
||||
git init &&
|
||||
>file &&
|
||||
git add file &&
|
||||
test_tick &&
|
||||
git commit -m "Initial" &&
|
||||
git checkout -b side &&
|
||||
>elif &&
|
||||
git add elif &&
|
||||
test_tick &&
|
||||
git commit -m "Second" &&
|
||||
git checkout master
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
setup_repository one &&
|
||||
setup_repository two &&
|
||||
(
|
||||
cd two && git branch another
|
||||
) &&
|
||||
git clone --mirror two three
|
||||
git clone one test
|
||||
'
|
||||
|
||||
cat > test/expect << EOF
|
||||
one/master
|
||||
one/side
|
||||
origin/HEAD -> origin/master
|
||||
origin/master
|
||||
origin/side
|
||||
three/another
|
||||
three/master
|
||||
three/side
|
||||
two/another
|
||||
two/master
|
||||
two/side
|
||||
EOF
|
||||
|
||||
test_expect_success 'git fetch --all' '
|
||||
(cd test &&
|
||||
git remote add one ../one &&
|
||||
git remote add two ../two &&
|
||||
git remote add three ../three &&
|
||||
git fetch --all &&
|
||||
git branch -r > output &&
|
||||
test_cmp expect output)
|
||||
'
|
||||
|
||||
test_expect_success 'git fetch --all should continue if a remote has errors' '
|
||||
(git clone one test2 &&
|
||||
cd test2 &&
|
||||
git remote add bad ../non-existing &&
|
||||
git remote add one ../one &&
|
||||
git remote add two ../two &&
|
||||
git remote add three ../three &&
|
||||
test_must_fail git fetch --all &&
|
||||
git branch -r > output &&
|
||||
test_cmp ../test/expect output)
|
||||
'
|
||||
|
||||
test_expect_success 'git fetch --all does not allow non-option arguments' '
|
||||
(cd test &&
|
||||
test_must_fail git fetch --all origin &&
|
||||
test_must_fail git fetch --all origin master)
|
||||
'
|
||||
|
||||
cat > expect << EOF
|
||||
origin/HEAD -> origin/master
|
||||
origin/master
|
||||
origin/side
|
||||
three/another
|
||||
three/master
|
||||
three/side
|
||||
EOF
|
||||
|
||||
test_expect_success 'git fetch --multiple (but only one remote)' '
|
||||
(git clone one test3 &&
|
||||
cd test3 &&
|
||||
git remote add three ../three &&
|
||||
git fetch --multiple three &&
|
||||
git branch -r > output &&
|
||||
test_cmp ../expect output)
|
||||
'
|
||||
|
||||
cat > expect << EOF
|
||||
one/master
|
||||
one/side
|
||||
two/another
|
||||
two/master
|
||||
two/side
|
||||
EOF
|
||||
|
||||
test_expect_success 'git fetch --multiple (two remotes)' '
|
||||
(git clone one test4 &&
|
||||
cd test4 &&
|
||||
git remote rm origin &&
|
||||
git remote add one ../one &&
|
||||
git remote add two ../two &&
|
||||
git fetch --multiple one two &&
|
||||
git branch -r > output &&
|
||||
test_cmp ../expect output)
|
||||
'
|
||||
|
||||
test_expect_success 'git fetch --multiple (bad remote names)' '
|
||||
(cd test4 &&
|
||||
test_must_fail git fetch --multiple four)
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'git fetch --all (skipFetchAll)' '
|
||||
(cd test4 &&
|
||||
for b in $(git branch -r)
|
||||
do
|
||||
git branch -r -d $b || break
|
||||
done &&
|
||||
git remote add three ../three &&
|
||||
git config remote.three.skipFetchAll true &&
|
||||
git fetch --all &&
|
||||
git branch -r > output &&
|
||||
test_cmp ../expect output)
|
||||
'
|
||||
|
||||
cat > expect << EOF
|
||||
one/master
|
||||
one/side
|
||||
three/another
|
||||
three/master
|
||||
three/side
|
||||
two/another
|
||||
two/master
|
||||
two/side
|
||||
EOF
|
||||
|
||||
test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' '
|
||||
(cd test4 &&
|
||||
for b in $(git branch -r)
|
||||
do
|
||||
git branch -r -d $b || break
|
||||
done &&
|
||||
git fetch --multiple one two three &&
|
||||
git branch -r > output &&
|
||||
test_cmp ../expect output)
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -162,6 +162,28 @@ test_expect_success 'empty email' '
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'del LF before empty (1)' '
|
||||
git show -s --pretty=format:"%s%n%-b%nThanks%n" HEAD^^ >actual &&
|
||||
test $(wc -l <actual) = 2
|
||||
'
|
||||
|
||||
test_expect_success 'del LF before empty (2)' '
|
||||
git show -s --pretty=format:"%s%n%-b%nThanks%n" HEAD >actual &&
|
||||
test $(wc -l <actual) = 6 &&
|
||||
grep "^$" actual
|
||||
'
|
||||
|
||||
test_expect_success 'add LF before non-empty (1)' '
|
||||
git show -s --pretty=format:"%s%+b%nThanks%n" HEAD^^ >actual &&
|
||||
test $(wc -l <actual) = 2
|
||||
'
|
||||
|
||||
test_expect_success 'add LF before non-empty (2)' '
|
||||
git show -s --pretty=format:"%s%+b%nThanks%n" HEAD >actual &&
|
||||
test $(wc -l <actual) = 6 &&
|
||||
grep "^$" actual
|
||||
'
|
||||
|
||||
test_expect_success '"%h %gD: %gs" is same as git-reflog' '
|
||||
git reflog >expect &&
|
||||
git log -g --format="%h %gD: %gs" >actual &&
|
||||
|
||||
61
t/t6017-rev-list-stdin.sh
Executable file
61
t/t6017-rev-list-stdin.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2009, Junio C Hamano
|
||||
#
|
||||
|
||||
test_description='log family learns --stdin'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
check () {
|
||||
for cmd in rev-list "log --stat"
|
||||
do
|
||||
for i in "$@"
|
||||
do
|
||||
printf "%s\n" $i
|
||||
done >input &&
|
||||
test_expect_success "check $cmd $*" '
|
||||
git $cmd $(cat input) >expect &&
|
||||
git $cmd --stdin <input >actual &&
|
||||
sed -e "s/^/input /" input &&
|
||||
sed -e "s/^/output /" expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
done
|
||||
}
|
||||
|
||||
them='1 2 3 4 5 6 7'
|
||||
|
||||
test_expect_success setup '
|
||||
(
|
||||
for i in 0 $them
|
||||
do
|
||||
for j in $them
|
||||
do
|
||||
echo $i.$j >file-$j &&
|
||||
git add file-$j || exit
|
||||
done &&
|
||||
test_tick &&
|
||||
git commit -m $i || exit
|
||||
done &&
|
||||
for i in $them
|
||||
do
|
||||
git checkout -b side-$i master~$i &&
|
||||
echo updated $i >file-$i &&
|
||||
git add file-$i &&
|
||||
test_tick &&
|
||||
git commit -m side-$i || exit
|
||||
done
|
||||
)
|
||||
'
|
||||
|
||||
check master
|
||||
check side-1 ^side-4
|
||||
check side-1 ^side-7 --
|
||||
check side-1 ^side-7 -- file-1
|
||||
check side-1 ^side-7 -- file-2
|
||||
check side-3 ^side-4 -- file-3
|
||||
check side-3 ^side-2
|
||||
check side-3 ^side-2 -- file-1
|
||||
|
||||
test_done
|
||||
@@ -77,6 +77,11 @@ test_expect_success 'test --no-replace-objects option' '
|
||||
git --no-replace-objects show $HASH2 | grep "A U Thor"
|
||||
'
|
||||
|
||||
test_expect_success 'test GIT_NO_REPLACE_OBJECTS env variable' '
|
||||
GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 | grep "author A U Thor" &&
|
||||
GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 | grep "A U Thor"
|
||||
'
|
||||
|
||||
cat >tag.sig <<EOF
|
||||
object $HASH2
|
||||
type commit
|
||||
@@ -202,6 +207,18 @@ test_expect_success 'fetch branch with replacement' '
|
||||
cd ..
|
||||
'
|
||||
|
||||
test_expect_success 'bisect and replacements' '
|
||||
git bisect start $HASH7 $HASH1 &&
|
||||
test "$S" = "$(git rev-parse --verify HEAD)" &&
|
||||
git bisect reset &&
|
||||
GIT_NO_REPLACE_OBJECTS=1 git bisect start $HASH7 $HASH1 &&
|
||||
test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
|
||||
git bisect reset &&
|
||||
git --no-replace-objects bisect start $HASH7 $HASH1 &&
|
||||
test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
|
||||
git bisect reset
|
||||
'
|
||||
|
||||
#
|
||||
#
|
||||
test_done
|
||||
|
||||
@@ -14,8 +14,8 @@ submodule and "git submodule update --rebase/--merge" does not detach the HEAD.
|
||||
|
||||
compare_head()
|
||||
{
|
||||
sha_master=`git-rev-list --max-count=1 master`
|
||||
sha_head=`git-rev-list --max-count=1 HEAD`
|
||||
sha_master=`git rev-list --max-count=1 master`
|
||||
sha_head=`git rev-list --max-count=1 HEAD`
|
||||
|
||||
test "$sha_master" = "$sha_head"
|
||||
}
|
||||
|
||||
114
t/t7509-commit.sh
Executable file
114
t/t7509-commit.sh
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2009 Erick Mattos
|
||||
#
|
||||
|
||||
test_description='git commit --reset-author'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
author_header () {
|
||||
git cat-file commit "$1" |
|
||||
sed -n -e '/^$/q' -e '/^author /p'
|
||||
}
|
||||
|
||||
message_body () {
|
||||
git cat-file commit "$1" |
|
||||
sed -e '1,/^$/d'
|
||||
}
|
||||
|
||||
test_expect_success '-C option copies authorship and message' '
|
||||
echo "Initial" >foo &&
|
||||
git add foo &&
|
||||
test_tick &&
|
||||
git commit -m "Initial Commit" --author Frigate\ \<flying@over.world\> &&
|
||||
git tag Initial &&
|
||||
echo "Test 1" >>foo &&
|
||||
test_tick &&
|
||||
git commit -a -C Initial &&
|
||||
author_header Initial >expect &&
|
||||
author_header HEAD >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
message_body Initial >expect &&
|
||||
message_body HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '-C option copies only the message with --reset-author' '
|
||||
echo "Test 2" >>foo &&
|
||||
test_tick &&
|
||||
git commit -a -C Initial --reset-author &&
|
||||
echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
|
||||
author_header HEAD >actual
|
||||
test_cmp expect actual &&
|
||||
|
||||
message_body Initial >expect &&
|
||||
message_body HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '-c option copies authorship and message' '
|
||||
echo "Test 3" >>foo &&
|
||||
test_tick &&
|
||||
EDITOR=: VISUAL=: git commit -a -c Initial &&
|
||||
author_header Initial >expect &&
|
||||
author_header HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '-c option copies only the message with --reset-author' '
|
||||
echo "Test 4" >>foo &&
|
||||
test_tick &&
|
||||
EDITOR=: VISUAL=: git commit -a -c Initial --reset-author &&
|
||||
echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
|
||||
author_header HEAD >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
message_body Initial >expect &&
|
||||
message_body HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--amend option copies authorship' '
|
||||
git checkout Initial &&
|
||||
echo "Test 5" >>foo &&
|
||||
test_tick &&
|
||||
git commit -a --amend -m "amend test" &&
|
||||
author_header Initial >expect &&
|
||||
author_header HEAD >actual &&
|
||||
|
||||
echo "amend test" >expect &&
|
||||
message_body HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--reset-author makes the commit ours even with --amend option' '
|
||||
git checkout Initial &&
|
||||
echo "Test 6" >>foo &&
|
||||
test_tick &&
|
||||
git commit -a --reset-author -m "Changed again" --amend &&
|
||||
echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
|
||||
author_header HEAD >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
echo "Changed again" >expect &&
|
||||
message_body HEAD >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--reset-author and --author are mutually exclusive' '
|
||||
git checkout Initial &&
|
||||
echo "Test 7" >>foo &&
|
||||
test_tick &&
|
||||
test_must_fail git commit -a --reset-author --author="Xyzzy <frotz@nitfol.xz>"
|
||||
'
|
||||
|
||||
test_expect_success '--reset-author should be rejected without -c/-C/--amend' '
|
||||
git checkout Initial &&
|
||||
echo "Test 7" >>foo &&
|
||||
test_tick &&
|
||||
test_must_fail git commit -a --reset-author -m done
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -22,15 +22,12 @@ test_expect_success 'setup' '
|
||||
git tag c2
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
custom message
|
||||
|
||||
Merge commit 'c2'
|
||||
EOF
|
||||
test_expect_success 'merge c2 with a custom message' '
|
||||
git reset --hard c1 &&
|
||||
echo >expected "custom message" &&
|
||||
git merge -m "custom message" c2 &&
|
||||
git cat-file commit HEAD | sed -e "1,/^$/d" > actual &&
|
||||
git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user