mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge git://repo.or.cz/git/spearce
This commit is contained in:
@@ -13,17 +13,83 @@ Fixes since v1.6.0.2
|
||||
* Continuing "git rebase -i" was also very confused when the user left
|
||||
some staged changes in the index after "edit".
|
||||
|
||||
* "git rebase -i" now honors the pre-rebase hook, just like the
|
||||
other rebase implementations "git rebase" and "git rebase -m".
|
||||
|
||||
* Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code"
|
||||
with the output redirected to /dev/null.
|
||||
|
||||
* "git diff --no-index" on binary files no longer outputs a bogus
|
||||
"diff --git" header line.
|
||||
|
||||
* Hunk headers in "git diff" default to using extended regular
|
||||
expressions, fixing some of the internal patterns on non-GNU
|
||||
platforms.
|
||||
|
||||
* New config "diff.*.xfuncname" exposes extended regular expressions
|
||||
for user specified hunk header patterns.
|
||||
|
||||
* "git stash apply sash@{1}" was fixed to error out. Prior versions
|
||||
would have applied stash@{0} incorrectly.
|
||||
|
||||
* "git stash apply" now offers a better suggestion on how to continue
|
||||
if the working tree is currently dirty.
|
||||
|
||||
* "git for-each-ref --format=%(subject)" fixed for commits with no
|
||||
no newline in the message body.
|
||||
|
||||
* "git remote" fixed to protect printf from user input.
|
||||
|
||||
* "git remote show -v" now displays all URLs of a remote.
|
||||
|
||||
* "git checkout -q" once again suppresses the locally modified file list.
|
||||
|
||||
* "git clone -q", "git fetch -q" asks remote side to not send
|
||||
progress messages, actually making their output quiet.
|
||||
|
||||
* Cross-directory renames are no longer used when creating packs. This
|
||||
allows more graceful behavior on filesystems like sshfs.
|
||||
|
||||
* Stale temporary files under $GIT_DIR/objects/pack are now cleaned up
|
||||
automatically by "git prune".
|
||||
|
||||
* "git merge" once again removes directories after the last file has
|
||||
been removed from it during the merge.
|
||||
|
||||
* "git blame -C -C" no longer segfaults while trying to pass blame if
|
||||
it encounters a submodule reference.
|
||||
|
||||
* "git svn" fixed to display an error message when 'set-tree' failed,
|
||||
instead of a Perl compile error.
|
||||
|
||||
* "git submodule" fixed to handle checking out a different commit
|
||||
than HEAD after initializing the submodule.
|
||||
|
||||
* The "git commit" error message when there are still unmerged
|
||||
files present was clarified to match "git write-tree".
|
||||
|
||||
* Some segfaults due to uncaught NULL pointers were fixed in multiple
|
||||
tools such as apply, reset, update-index.
|
||||
|
||||
* Solaris builds now default to OLD_ICONV=1 to avoid compile warnings.
|
||||
|
||||
* "Git.pm" tests relied on unnecessarily more recent version of Perl.
|
||||
|
||||
* "gitweb" triggered undef warning on commits without log messages.
|
||||
|
||||
* "gitweb" triggered undef warnings on missing trees.
|
||||
|
||||
* "gitweb" now removes PATH_INFO from its URLs so users don't have
|
||||
to manually set the URL in the gitweb configuration.
|
||||
|
||||
* Bash completion removed support for legacy "git-fetch", "git-push"
|
||||
and "git-pull" as these are no longer installed. Dashless form
|
||||
("git fetch") is still however supported.
|
||||
|
||||
Many other documentation updates.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.6.0.2-32-g8d11fde
|
||||
O=v1.6.0.2-76-gd70b4a8
|
||||
echo O=$(git describe maint)
|
||||
git shortlog --no-merges $O..maint
|
||||
|
||||
@@ -59,7 +59,7 @@ on.
|
||||
|
||||
* "git daemon" learned --max-connections=<count> option.
|
||||
|
||||
* "git diff" learned to mimick --suppress-blank-empty from GNU diff via a
|
||||
* "git diff" learned to mimic --suppress-blank-empty from GNU diff via a
|
||||
configuration option.
|
||||
|
||||
* "git diff" learned to put more sensible hunk headers for Python and
|
||||
@@ -121,7 +121,7 @@ release, unless otherwise noted.
|
||||
is a path in it).
|
||||
|
||||
* "git diff --stdin" used to take two trees on a line and compared them,
|
||||
but we droppped support for such a use case long time ago. This has
|
||||
but we dropped support for such a use case long time ago. This has
|
||||
been resurrected.
|
||||
|
||||
* "git filter-branch" failed to rewrite a tag name with slashes in it.
|
||||
|
||||
@@ -117,6 +117,15 @@ core.fileMode::
|
||||
the working copy are ignored; useful on broken filesystems like FAT.
|
||||
See linkgit:git-update-index[1]. True by default.
|
||||
|
||||
core.ignoreCygwinFSTricks::
|
||||
This option is only used by Cygwin implementation of Git. If false,
|
||||
the Cygwin stat() and lstat() functions are used. This may be useful
|
||||
if your repository consists of a few separate directories joined in
|
||||
one hierarchy using Cygwin mount. If true, Git uses native Win32 API
|
||||
whenever it is possible and falls back to Cygwin functions only to
|
||||
handle symbol links. The native mode is more than twice faster than
|
||||
normal Cygwin l/stat() functions. True by default.
|
||||
|
||||
core.trustctime::
|
||||
If false, the ctime differences between the index and the
|
||||
working copy are ignored; useful when the inode change time
|
||||
@@ -363,8 +372,17 @@ core.pager::
|
||||
variable. Note that git sets the `LESS` environment
|
||||
variable to `FRSX` if it is unset when it runs the
|
||||
pager. One can change these settings by setting the
|
||||
`LESS` variable to some other value or by giving the
|
||||
`core.pager` option a value such as "`less -+FRSX`".
|
||||
`LESS` variable to some other value. Alternately,
|
||||
these settings can be overridden on a project or
|
||||
global basis by setting the `core.pager` option.
|
||||
Setting `core.pager` has no affect on the `LESS`
|
||||
environment variable behaviour above, so if you want
|
||||
to override git's default settings this way, you need
|
||||
to be explicit. For example, to disable the S option
|
||||
in a backward compatible manner, set `core.pager`
|
||||
to "`less -+$LESS -FRX`". This will be passed to the
|
||||
shell by git, which will translate the final command to
|
||||
"`LESS=FRSX less -+FRSX -FRX`".
|
||||
|
||||
core.whitespace::
|
||||
A comma separated list of common whitespace problems to
|
||||
@@ -918,6 +936,14 @@ man.<tool>.path::
|
||||
Override the path for the given tool that may be used to
|
||||
display help in the 'man' format. See linkgit:git-help[1].
|
||||
|
||||
merge.conflictstyle::
|
||||
Specify the style in which conflicted hunks are written out to
|
||||
working tree files upon merge. The default is "merge", which
|
||||
shows `<<<<<<<` conflict marker, change made by one side,
|
||||
`=======` marker, change made by the other side, and then
|
||||
`>>>>>>>` marker. An alternate style, "diff3", adds `|||||||`
|
||||
marker and the original text before `=======` marker.
|
||||
|
||||
mergetool.<tool>.path::
|
||||
Override the path for the given tool. This is useful in case
|
||||
your tool is not in the PATH.
|
||||
|
||||
@@ -65,6 +65,9 @@ endif::git-format-patch[]
|
||||
can be set with "--dirstat=limit". Changes in a child directory is not
|
||||
counted for the parent directory, unless "--cumulative" is used.
|
||||
|
||||
--dirstat-by-file[=limit]::
|
||||
Same as --dirstat, but counts changed files instead of lines.
|
||||
|
||||
--summary::
|
||||
Output a condensed summary of extended header information
|
||||
such as creations, renames and mode changes.
|
||||
|
||||
@@ -14,7 +14,8 @@ SYNOPSIS
|
||||
[--allow-binary-replacement | --binary] [--reject] [-z]
|
||||
[-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached]
|
||||
[--whitespace=<nowarn|warn|fix|error|error-all>]
|
||||
[--exclude=PATH] [--directory=<root>] [--verbose] [<patch>...]
|
||||
[--exclude=PATH] [--include=PATH] [--directory=<root>]
|
||||
[--verbose] [<patch>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -137,6 +138,17 @@ discouraged.
|
||||
be useful when importing patchsets, where you want to exclude certain
|
||||
files or directories.
|
||||
|
||||
--include=<path-pattern>::
|
||||
Apply changes to files matching the given path pattern. This can
|
||||
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
|
||||
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
|
||||
on the command line, and ignored if there is any include pattern.
|
||||
|
||||
--whitespace=<action>::
|
||||
When applying a patch, detect a new or modified line that has
|
||||
whitespace errors. What are considered whitespace errors is
|
||||
|
||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
|
||||
'git checkout' [<tree-ish>] [--] <paths>...
|
||||
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -27,14 +27,20 @@ the first namespace level.
|
||||
|
||||
When <paths> are given, this command does *not* switch
|
||||
branches. It updates the named paths in the working tree from
|
||||
the index file (i.e. it runs `git checkout-index -f -u`), or
|
||||
from a named commit. In
|
||||
this case, the `-f` and `-b` options are meaningless and giving
|
||||
the index file, or from a named commit. In
|
||||
this case, the `-b` options is meaningless and giving
|
||||
either of them results in an error. <tree-ish> argument can be
|
||||
used to specify a specific tree-ish (i.e. commit, tag or tree)
|
||||
to update the index for the given paths before updating the
|
||||
working tree.
|
||||
|
||||
The index may contain unmerged entries after a failed merge. By
|
||||
default, if you try to check out such an entry from the index, the
|
||||
checkout operation will fail and nothing will be checked out.
|
||||
Using -f will ignore these unmerged entries. The contents from a
|
||||
specific side of the merge can be checked out of the index by
|
||||
using --ours or --theirs. With -m, changes made to the working tree
|
||||
file can be discarded to recreate the original conflicted merge result.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@@ -42,8 +48,17 @@ OPTIONS
|
||||
Quiet, suppress feedback messages.
|
||||
|
||||
-f::
|
||||
Proceed even if the index or the working tree differs
|
||||
from HEAD. This is used to throw away local changes.
|
||||
When switching branches, proceed even if the index or the
|
||||
working tree differs from HEAD. This is used to throw away
|
||||
local changes.
|
||||
+
|
||||
When checking out paths from the index, do not fail upon unmerged
|
||||
entries; instead, unmerged entries are ignored.
|
||||
|
||||
--ours::
|
||||
--theirs::
|
||||
When checking out paths from the index, check out stage #2
|
||||
('ours') or #3 ('theirs') for unmerged paths.
|
||||
|
||||
-b::
|
||||
Create a new branch named <new_branch> and start it at
|
||||
@@ -84,7 +99,9 @@ exlicitly give a name with '-b' in such a case.
|
||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
||||
|
||||
-m::
|
||||
If you have local modifications to one or more files that
|
||||
--merge::
|
||||
When switching branches,
|
||||
if you have local modifications to one or more files that
|
||||
are different between the current branch and the branch to
|
||||
which you are switching, the command refuses to switch
|
||||
branches in order to preserve your modifications in context.
|
||||
@@ -96,6 +113,16 @@ When a merge conflict happens, the index entries for conflicting
|
||||
paths are left unmerged, and you need to resolve the conflicts
|
||||
and mark the resolved paths with `git add` (or `git rm` if the merge
|
||||
should result in deletion of the path).
|
||||
+
|
||||
When checking out paths from the index, this option lets you recreate
|
||||
the conflicted merge in the specified paths.
|
||||
|
||||
--conflict=<style>::
|
||||
The same as --merge option above, but changes the way the
|
||||
conflicting hunks are presented, overriding the
|
||||
merge.conflictstyle configuration variable. Possible values are
|
||||
"merge" (default) and "diff3" (in addition to what is shown by
|
||||
"merge" style, shows the original contents).
|
||||
|
||||
<new_branch>::
|
||||
Name for the new branch.
|
||||
|
||||
@@ -15,6 +15,7 @@ SYNOPSIS
|
||||
[-E | --extended-regexp] [-G | --basic-regexp]
|
||||
[-F | --fixed-strings] [-n]
|
||||
[-l | --files-with-matches] [-L | --files-without-match]
|
||||
[-z | --null]
|
||||
[-c | --count] [--all-match]
|
||||
[-A <post-context>] [-B <pre-context>] [-C <context>]
|
||||
[-f <file>] [-e] <pattern>
|
||||
@@ -94,6 +95,11 @@ OPTIONS
|
||||
For better compatibility with 'git-diff', --name-only is a
|
||||
synonym for --files-with-matches.
|
||||
|
||||
-z::
|
||||
--null::
|
||||
Output \0 instead of the character that normally follows a
|
||||
file name.
|
||||
|
||||
-c::
|
||||
--count::
|
||||
Instead of showing every matched line, show the number of
|
||||
|
||||
@@ -8,7 +8,7 @@ git-log - Show commit logs
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git log' <option>...
|
||||
'git log' [<options>] [<since>..<until>] [[\--] <path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -57,8 +57,11 @@ include::diff-options.txt[]
|
||||
Note that only message is considered, if also a diff is shown
|
||||
its size is not included.
|
||||
|
||||
<path>...::
|
||||
Show only commits that affect any of the specified paths.
|
||||
[\--] <path>...::
|
||||
Show only commits that affect any of the specified paths. To
|
||||
prevent confusion with options and branch names, paths may need
|
||||
to be prefixed with "\-- " to separate them from options or
|
||||
refnames.
|
||||
|
||||
|
||||
include::rev-list-options.txt[]
|
||||
|
||||
@@ -119,6 +119,71 @@ When there are conflicts, these things happen:
|
||||
same and the index entries for them stay as they were,
|
||||
i.e. matching `HEAD`.
|
||||
|
||||
HOW CONFLICTS ARE PRESENTED
|
||||
---------------------------
|
||||
|
||||
During a merge, the working tree files are updated to reflect the result
|
||||
of the merge. Among the changes made to the common ancestor's version,
|
||||
non-overlapping ones (that is, you changed an area of the file while the
|
||||
other side left that area intact, or vice versa) are incorporated in the
|
||||
final result verbatim. When both sides made changes to the same area,
|
||||
however, git cannot randomly pick one side over the other, and asks you to
|
||||
resolve it by leaving what both sides did to that area.
|
||||
|
||||
By default, git uses the same style as that is used by "merge" program
|
||||
from the RCS suite to present such a conflicted hunk, like this:
|
||||
|
||||
------------
|
||||
Here are lines that are either unchanged from the common
|
||||
ancestor, or cleanly resolved because only one side changed.
|
||||
<<<<<<< yours:sample.txt
|
||||
Conflict resolution is hard;
|
||||
let's go shopping.
|
||||
=======
|
||||
Git makes conflict resolution easy.
|
||||
>>>>>>> theirs:sample.txt
|
||||
And here is another line that is cleanly resolved or unmodified.
|
||||
------------
|
||||
|
||||
The area a pair of conflicting changes happened is marked with markers
|
||||
"`<<<<<<<`", "`=======`", and "`>>>>>>>`". The part before the "`=======`"
|
||||
is typically your side, and the part after it is typically their side.
|
||||
|
||||
The default format does not show what the original said in the conflicted
|
||||
area. You cannot tell how many lines are deleted and replaced with the
|
||||
Barbie's remark by your side. The only thing you can tell is that your
|
||||
side wants to say it is hard and you'd prefer to go shopping, while the
|
||||
other side wants to claim it is easy.
|
||||
|
||||
An alternative style can be used by setting the "merge.conflictstyle"
|
||||
configuration variable to "diff3". In "diff3" style, the above conflict
|
||||
may look like this:
|
||||
|
||||
------------
|
||||
Here are lines that are either unchanged from the common
|
||||
ancestor, or cleanly resolved because only one side changed.
|
||||
<<<<<<< yours:sample.txt
|
||||
Conflict resolution is hard;
|
||||
let's go shopping.
|
||||
|||||||
|
||||
Conflict resolution is hard.
|
||||
=======
|
||||
Git makes conflict resolution easy.
|
||||
>>>>>>> theirs:sample.txt
|
||||
And here is another line that is cleanly resolved or unmodified.
|
||||
------------
|
||||
|
||||
In addition to the "`<<<<<<<`", "`=======`", and "`>>>>>>>`" markers, it uses
|
||||
another "`|||||||`" marker that is followed by the original text. You can
|
||||
tell that the original just stated a fact, and your side simply gave in to
|
||||
that statement and gave up, while the other side tried to have a more
|
||||
positive attitude. You can sometimes come up with a better resolution by
|
||||
viewing the original.
|
||||
|
||||
|
||||
HOW TO RESOLVE CONFLICTS
|
||||
------------------------
|
||||
|
||||
After seeing a conflict, you can do two things:
|
||||
|
||||
* Decide not to merge. The only clean-up you need are to reset
|
||||
|
||||
@@ -8,7 +8,7 @@ git-prune - Prune all unreachable objects from the object database
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-prune' [-n] [--expire <expire>] [--] [<head>...]
|
||||
'git-prune' [-n] [-v] [--expire <expire>] [--] [<head>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -34,6 +34,9 @@ OPTIONS
|
||||
Do not remove anything; just report what it would
|
||||
remove.
|
||||
|
||||
-v::
|
||||
Report all removed objects.
|
||||
|
||||
\--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ git-push - Update remote refs along with associated objects
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
|
||||
[--repo=all] [-f | --force] [-v | --verbose]
|
||||
'git push' [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
|
||||
[--repo=<repository>] [-f | --force] [-v | --verbose]
|
||||
[<repository> <refspec>...]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -101,9 +101,23 @@ nor in any Push line of the corresponding remotes file---see below).
|
||||
This flag disables the check. This can cause the
|
||||
remote repository to lose commits; use it with care.
|
||||
|
||||
--repo=<repo>::
|
||||
When no repository is specified the command defaults to
|
||||
"origin"; this overrides it.
|
||||
--repo=<repository>::
|
||||
This option is only relevant if no <repository> argument is
|
||||
passed in the invocation. In this case, 'git-push' derives the
|
||||
remote name from the current branch: If it tracks a remote
|
||||
branch, then that remote repository is pushed to. Otherwise,
|
||||
the name "origin" is used. For this latter case, this option
|
||||
can be used to override the name "origin". In other words,
|
||||
the difference between these two commands
|
||||
+
|
||||
--------------------------
|
||||
git push public #1
|
||||
git push --repo=public #2
|
||||
--------------------------
|
||||
+
|
||||
is that #1 always pushes to "public" whereas #2 pushes to "public"
|
||||
only if the current branch does not track a remote branch. This is
|
||||
useful if you write an alias or script around 'git-push'.
|
||||
|
||||
--thin::
|
||||
--no-thin::
|
||||
|
||||
@@ -212,7 +212,7 @@ output after two-tree merge.
|
||||
|
||||
Case #3 is slightly tricky and needs explanation. The result from this
|
||||
rule logically should be to remove the path if the user staged the removal
|
||||
of the path and then swiching to a new branch. That however will prevent
|
||||
of the path and then switching to a new branch. That however will prevent
|
||||
the initial checkout from happening, so the rule is modified to use M (new
|
||||
tree) only when the contents of the index is empty. Otherwise the removal
|
||||
of the path is kept as long as $H and $M are the same.
|
||||
|
||||
@@ -92,7 +92,7 @@ branch to another, to pretend that you forked the topic branch
|
||||
from the latter branch, using `rebase --onto`.
|
||||
|
||||
First let's assume your 'topic' is based on branch 'next'.
|
||||
For example feature developed in 'topic' depends on some
|
||||
For example, a feature developed in 'topic' depends on some
|
||||
functionality which is found in 'next'.
|
||||
|
||||
------------
|
||||
@@ -103,9 +103,9 @@ functionality which is found in 'next'.
|
||||
o---o---o topic
|
||||
------------
|
||||
|
||||
We would want to make 'topic' forked from branch 'master',
|
||||
for example because the functionality 'topic' branch depend on
|
||||
got merged into more stable 'master' branch, like this:
|
||||
We want to make 'topic' forked from branch 'master'; for example,
|
||||
because the functionality on which 'topic' depends was merged into the
|
||||
more stable 'master' branch. We want our tree to look like this:
|
||||
|
||||
------------
|
||||
o---o---o---o---o master
|
||||
|
||||
@@ -32,9 +32,9 @@ SYNOPSIS
|
||||
[ \--cherry-pick ]
|
||||
[ \--encoding[=<encoding>] ]
|
||||
[ \--(author|committer|grep)=<pattern> ]
|
||||
[ \--regexp-ignore-case | \-i ]
|
||||
[ \--extended-regexp | \-E ]
|
||||
[ \--fixed-strings | \-F ]
|
||||
[ \--regexp-ignore-case | -i ]
|
||||
[ \--extended-regexp | -E ]
|
||||
[ \--fixed-strings | -F ]
|
||||
[ \--date={local|relative|default|iso|rfc|short} ]
|
||||
[ [\--objects | \--objects-edge] [ \--unpacked ] ]
|
||||
[ \--pretty | \--header ]
|
||||
|
||||
@@ -11,7 +11,6 @@ SYNOPSIS
|
||||
'git send-email' [options] <file|directory> [... file|directory]
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Takes the patches given on the command line and emails them out.
|
||||
@@ -20,12 +19,16 @@ The header of the email is configurable by command line options. If not
|
||||
specified on the command line, the user will be prompted with a ReadLine
|
||||
enabled interface to provide the necessary information.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
The options available are:
|
||||
|
||||
Composing
|
||||
~~~~~~~~~
|
||||
|
||||
--bcc::
|
||||
Specify a "Bcc:" value for each email.
|
||||
Specify a "Bcc:" value for each email. Default is the value of
|
||||
'sendemail.bcc'.
|
||||
+
|
||||
The --bcc option must be repeated for each user you want on the bcc list.
|
||||
|
||||
@@ -34,22 +37,6 @@ The --bcc option must be repeated for each user you want on the bcc list.
|
||||
+
|
||||
The --cc option must be repeated for each user you want on the cc list.
|
||||
|
||||
--cc-cmd::
|
||||
Specify a command to execute once per patch file which
|
||||
should generate patch file specific "Cc:" entries.
|
||||
Output of this command must be single email address per line.
|
||||
Default is the value of 'sendemail.cccmd' configuration value.
|
||||
|
||||
--chain-reply-to::
|
||||
--no-chain-reply-to::
|
||||
If this is set, each email will be sent as a reply to the previous
|
||||
email sent. If disabled with "--no-chain-reply-to", all emails after
|
||||
the first will be sent as replies to the first email sent. When using
|
||||
this, it is recommended that the first file given be an overview of the
|
||||
entire patch series.
|
||||
Default is the value of the 'sendemail.chainreplyto' configuration
|
||||
value; if that is unspecified, default to --chain-reply-to.
|
||||
|
||||
--compose::
|
||||
Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an
|
||||
introductory message for the patch series.
|
||||
@@ -66,22 +53,47 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
Only necessary if --compose is also set. If --compose
|
||||
is not set, this will be prompted for.
|
||||
|
||||
--signed-off-by-cc::
|
||||
--no-signed-off-by-cc::
|
||||
If this is set, add emails found in Signed-off-by: or Cc: lines to the
|
||||
cc list.
|
||||
Default is the value of 'sendemail.signedoffcc' configuration value;
|
||||
if that is unspecified, default to --signed-off-by-cc.
|
||||
--subject::
|
||||
Specify the initial subject of the email thread.
|
||||
Only necessary if --compose is also set. If --compose
|
||||
is not set, this will be prompted for.
|
||||
|
||||
--quiet::
|
||||
Make git-send-email less verbose. One line per email should be
|
||||
all that is output.
|
||||
--to::
|
||||
Specify the primary recipient of the emails generated. Generally, this
|
||||
will be the upstream maintainer of the project involved. Default is the
|
||||
value of the 'sendemail.to' configuration value; if that is unspecified,
|
||||
this will be prompted for.
|
||||
+
|
||||
The --to option must be repeated for each user you want on the to list.
|
||||
|
||||
--identity::
|
||||
A configuration identity. When given, causes values in the
|
||||
'sendemail.<identity>' subsection to take precedence over
|
||||
values in the 'sendemail' section. The default identity is
|
||||
the value of 'sendemail.identity'.
|
||||
|
||||
Sending
|
||||
~~~~~~~
|
||||
|
||||
--envelope-sender::
|
||||
Specify the envelope sender used to send the emails.
|
||||
This is useful if your default address is not the address that is
|
||||
subscribed to a list. If you use the sendmail binary, you must have
|
||||
suitable privileges for the -f parameter. 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::
|
||||
Specify the encryption to use, either 'ssl' or 'tls'. Any other
|
||||
value reverts to plain SMTP. Default is the value of
|
||||
'sendemail.smtpencryption'.
|
||||
|
||||
--smtp-pass::
|
||||
Password for SMTP-AUTH. The argument is optional: If no
|
||||
argument is specified, then the empty string is used as
|
||||
the password. Default is the value of 'sendemail.smtppass',
|
||||
however '--smtp-pass' always overrides this value.
|
||||
+
|
||||
Furthermore, passwords need not be specified in configuration files
|
||||
or on the command line. If a username has been specified (with
|
||||
'--smtp-user' or a 'sendemail.smtpuser'), but no password has been
|
||||
specified (with '--smtp-pass' or 'sendemail.smtppass'), then the
|
||||
user is prompted for a password while the input is masked for privacy.
|
||||
|
||||
--smtp-server::
|
||||
If set, specifies the outgoing SMTP server to use (e.g.
|
||||
@@ -96,61 +108,44 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
--smtp-server-port::
|
||||
Specifies a port different from the default port (SMTP
|
||||
servers typically listen to smtp port 25 and ssmtp port
|
||||
465).
|
||||
|
||||
--smtp-user::
|
||||
Username for SMTP-AUTH. In place of this option, the following
|
||||
configuration variables can be specified:
|
||||
+
|
||||
--
|
||||
* sendemail.smtpuser
|
||||
* sendemail.<identity>.smtpuser (see sendemail.identity).
|
||||
--
|
||||
+
|
||||
However, --smtp-user always overrides these variables.
|
||||
+
|
||||
If a username is not specified (with --smtp-user or a
|
||||
configuration variable), then authentication is not attempted.
|
||||
|
||||
--smtp-pass::
|
||||
Password for SMTP-AUTH. The argument is optional: If no
|
||||
argument is specified, then the empty string is used as
|
||||
the password.
|
||||
+
|
||||
In place of this option, the following configuration variables
|
||||
can be specified:
|
||||
+
|
||||
--
|
||||
* sendemail.smtppass
|
||||
* sendemail.<identity>.smtppass (see sendemail.identity).
|
||||
--
|
||||
+
|
||||
However, --smtp-pass always overrides these variables.
|
||||
+
|
||||
Furthermore, passwords need not be specified in configuration files
|
||||
or on the command line. If a username has been specified (with
|
||||
--smtp-user or a configuration variable), but no password has been
|
||||
specified (with --smtp-pass or a configuration variable), then the
|
||||
user is prompted for a password while the input is masked for privacy.
|
||||
|
||||
--smtp-encryption::
|
||||
Specify the encryption to use, either 'ssl' or 'tls'. Any other
|
||||
value reverts to plain SMTP. Default is the value of
|
||||
'sendemail.smtpencryption'.
|
||||
465). This can be set with 'sendemail.smtpserverport'.
|
||||
|
||||
--smtp-ssl::
|
||||
Legacy alias for '--smtp-encryption=ssl'.
|
||||
Legacy alias for '--smtp-encryption ssl'.
|
||||
|
||||
--subject::
|
||||
Specify the initial subject of the email thread.
|
||||
Only necessary if --compose is also set. If --compose
|
||||
is not set, this will be prompted for.
|
||||
--smtp-user::
|
||||
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
|
||||
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
|
||||
then authentication is not attempted.
|
||||
|
||||
--suppress-from::
|
||||
--no-suppress-from::
|
||||
If this is set, do not add the From: address to the cc: list.
|
||||
Default is the value of 'sendemail.suppressfrom' configuration value;
|
||||
if that is unspecified, default to --no-suppress-from.
|
||||
|
||||
Automating
|
||||
~~~~~~~~~~
|
||||
|
||||
--cc-cmd::
|
||||
Specify a command to execute once per patch file which
|
||||
should generate patch file specific "Cc:" entries.
|
||||
Output of this command must be single email address per line.
|
||||
Default is the value of 'sendemail.cccmd' configuration value.
|
||||
|
||||
--[no-]chain-reply-to::
|
||||
If this is set, each email will be sent as a reply to the previous
|
||||
email sent. If disabled with "--no-chain-reply-to", all emails after
|
||||
the first will be sent as replies to the first email sent. When using
|
||||
this, it is recommended that the first file given be an overview of the
|
||||
entire patch series. Default is the value of the 'sendemail.chainreplyto'
|
||||
configuration value; if that is unspecified, default to --chain-reply-to.
|
||||
|
||||
--identity::
|
||||
A configuration identity. When given, causes values in the
|
||||
'sendemail.<identity>' subsection to take precedence over
|
||||
values in the 'sendemail' section. The default identity is
|
||||
the value of 'sendemail.identity'.
|
||||
|
||||
--[no-]signed-off-by-cc::
|
||||
If this is set, add emails found in Signed-off-by: or Cc: lines to the
|
||||
cc list. Default is the value of 'sendemail.signedoffbycc' configuration
|
||||
value; if that is unspecified, default to --signed-off-by-cc.
|
||||
|
||||
--suppress-cc::
|
||||
Specify an additional category of recipients to suppress the
|
||||
@@ -163,44 +158,43 @@ user is prompted for a password while the input is masked for privacy.
|
||||
if that is unspecified, default to 'self' if --suppress-from is
|
||||
specified, as well as 'sob' if --no-signed-off-cc is specified.
|
||||
|
||||
--thread::
|
||||
--no-thread::
|
||||
--[no-]suppress-from::
|
||||
If this is set, do not add the From: address to the cc: list.
|
||||
Default is the value of 'sendemail.suppressfrom' configuration
|
||||
value; if that is unspecified, default to --no-suppress-from.
|
||||
|
||||
--[no-]thread::
|
||||
If this is set, the In-Reply-To header will be set on each email sent.
|
||||
If disabled with "--no-thread", no emails will have the In-Reply-To
|
||||
header set.
|
||||
Default is the value of the 'sendemail.thread' configuration value;
|
||||
if that is unspecified, default to --thread.
|
||||
header set. Default is the value of the 'sendemail.thread' configuration
|
||||
value; if that is unspecified, default to --thread.
|
||||
|
||||
|
||||
Administering
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
--dry-run::
|
||||
Do everything except actually send the emails.
|
||||
|
||||
--envelope-sender::
|
||||
Specify the envelope sender used to send the emails.
|
||||
This is useful if your default address is not the address that is
|
||||
subscribed to a list. If you use the sendmail binary, you must have
|
||||
suitable privileges for the -f parameter.
|
||||
Default is the value of the 'sendemail.envelopesender' configuration
|
||||
variable; if that is unspecified, choosing the envelope sender is left
|
||||
to your MTA.
|
||||
--quiet::
|
||||
Make git-send-email less verbose. One line per email should be
|
||||
all that is output.
|
||||
|
||||
--to::
|
||||
Specify the primary recipient of the emails generated.
|
||||
Generally, this will be the upstream maintainer of the
|
||||
project involved.
|
||||
Default is the value of the 'sendemail.to' configuration value;
|
||||
if that is unspecified, this will be prompted for.
|
||||
--[no-]validate::
|
||||
Perform sanity checks on patches.
|
||||
Currently, validation means the following:
|
||||
+
|
||||
The --to option must be repeated for each user you want on the to list.
|
||||
--
|
||||
* Warn of patches that contain lines longer than 998 characters; this
|
||||
is due to SMTP limits as described by http://www.ietf.org/rfc/rfc2821.txt.
|
||||
--
|
||||
+
|
||||
Default is the value of 'sendemail.validate'; if this is not set,
|
||||
default to '--validate'.
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
sendemail.identity::
|
||||
The default configuration identity. When specified,
|
||||
'sendemail.<identity>.<item>' will have higher precedence than
|
||||
'sendemail.<item>'. This is useful to declare multiple SMTP
|
||||
identities and to hoist sensitive authentication information
|
||||
out of the repository and into the global configuration file.
|
||||
|
||||
sendemail.aliasesfile::
|
||||
To avoid typing long email addresses, point this to one or more
|
||||
@@ -210,38 +204,6 @@ sendemail.aliasfiletype::
|
||||
Format of the file(s) specified in sendemail.aliasesfile. Must be
|
||||
one of 'mutt', 'mailrc', 'pine', or 'gnus'.
|
||||
|
||||
sendemail.to::
|
||||
Email address (or alias) to always send to.
|
||||
|
||||
sendemail.cccmd::
|
||||
Command to execute to generate per patch file specific "Cc:"s.
|
||||
|
||||
sendemail.bcc::
|
||||
Email address (or alias) to always bcc.
|
||||
|
||||
sendemail.chainreplyto::
|
||||
Boolean value specifying the default to the '--chain_reply_to'
|
||||
parameter.
|
||||
|
||||
sendemail.smtpserver::
|
||||
Default SMTP server to use.
|
||||
|
||||
sendemail.smtpserverport::
|
||||
Default SMTP server port to use.
|
||||
|
||||
sendemail.smtpuser::
|
||||
Default SMTP-AUTH username.
|
||||
|
||||
sendemail.smtppass::
|
||||
Default SMTP-AUTH password.
|
||||
|
||||
sendemail.smtpencryption::
|
||||
Default encryption method. Use 'ssl' for SSL (and specify an
|
||||
appropriate port), or 'tls' for TLS. Takes precedence over
|
||||
'smtpssl' if both are specified.
|
||||
|
||||
sendemail.smtpssl::
|
||||
Legacy boolean that sets 'smtpencryption=ssl' if enabled.
|
||||
|
||||
Author
|
||||
------
|
||||
@@ -250,10 +212,12 @@ Written by Ryan Anderson <ryan@michonline.com>
|
||||
git-send-email is originally based upon
|
||||
send_lots_of_email.pl by Greg Kroah-Hartman.
|
||||
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Ryan Anderson
|
||||
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[1] suite
|
||||
|
||||
@@ -149,6 +149,22 @@ and have no uncommitted changes.
|
||||
is very strongly discouraged.
|
||||
--
|
||||
|
||||
'branch'::
|
||||
Create a branch in the SVN repository.
|
||||
|
||||
-m;;
|
||||
--message;;
|
||||
Allows to specify the commit message.
|
||||
|
||||
-t;;
|
||||
--tag;;
|
||||
Create a tag by using the tags_subdir instead of the branches_subdir
|
||||
specified during git svn init.
|
||||
|
||||
'tag'::
|
||||
Create a tag in the SVN repository. This is a shorthand for
|
||||
'branch -t'.
|
||||
|
||||
'log'::
|
||||
This should make it easy to look up svn log messages when svn
|
||||
users refer to -r/--revision numbers.
|
||||
@@ -372,7 +388,8 @@ Passed directly to 'git-rebase' when using 'dcommit' if a
|
||||
-n::
|
||||
--dry-run::
|
||||
|
||||
This can be used with the 'dcommit' and 'rebase' commands.
|
||||
This can be used with the 'dcommit', 'rebase', 'branch' and 'tag'
|
||||
commands.
|
||||
|
||||
For 'dcommit', print out the series of git arguments that would show
|
||||
which diffs would be committed to SVN.
|
||||
@@ -381,6 +398,9 @@ For 'rebase', display the local branch associated with the upstream svn
|
||||
repository associated with the current branch and the URL of svn
|
||||
repository that will be fetched from.
|
||||
|
||||
For 'branch' and 'tag', display the urls that will be used for copying when
|
||||
creating the branch or tag.
|
||||
|
||||
--
|
||||
|
||||
ADVANCED OPTIONS
|
||||
@@ -473,7 +493,7 @@ Tracking and contributing to the trunk of a Subversion-managed project:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
# Clone a repo (like git clone):
|
||||
git svn clone http://svn.foo.org/project/trunk
|
||||
git svn clone http://svn.example.com/project/trunk
|
||||
# Enter the newly cloned directory:
|
||||
cd trunk
|
||||
# You should be on master branch, double-check with git-branch
|
||||
@@ -495,9 +515,11 @@ Tracking and contributing to an entire Subversion-managed project
|
||||
|
||||
------------------------------------------------------------------------
|
||||
# Clone a repo (like git clone):
|
||||
git svn clone http://svn.foo.org/project -T trunk -b branches -t tags
|
||||
git svn clone http://svn.example.com/project -T trunk -b branches -t tags
|
||||
# View all branches and tags you have cloned:
|
||||
git branch -r
|
||||
# Create a new branch in SVN
|
||||
git svn branch waldo
|
||||
# Reset your master to trunk (or any other branch, replacing 'trunk'
|
||||
# with the appropriate name):
|
||||
git reset --hard remotes/trunk
|
||||
@@ -514,7 +536,7 @@ have each person clone that repository with 'git-clone':
|
||||
|
||||
------------------------------------------------------------------------
|
||||
# Do the initial import on a server
|
||||
ssh server "cd /pub && git svn clone http://svn.foo.org/project
|
||||
ssh server "cd /pub && git svn clone http://svn.example.com/project
|
||||
# Clone locally - make sure the refs/remotes/ space matches the server
|
||||
mkdir project
|
||||
cd project
|
||||
@@ -523,7 +545,7 @@ have each person clone that repository with 'git-clone':
|
||||
git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
|
||||
git fetch
|
||||
# Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server)
|
||||
git svn init http://svn.foo.org/project
|
||||
git svn init http://svn.example.com/project
|
||||
# Pull the latest changes from Subversion
|
||||
git svn rebase
|
||||
------------------------------------------------------------------------
|
||||
|
||||
@@ -26,6 +26,7 @@ The following browsers (or commands) are currently supported:
|
||||
* lynx
|
||||
* dillo
|
||||
* open (this is the default under Mac OS X GUI)
|
||||
* start (this is the default under MinGW)
|
||||
|
||||
Custom commands may also be specified.
|
||||
|
||||
|
||||
@@ -288,13 +288,13 @@ for paths.
|
||||
*.tex diff=tex
|
||||
------------------------
|
||||
|
||||
Then, you would define a "diff.tex.funcname" configuration to
|
||||
Then, you would define a "diff.tex.xfuncname" configuration to
|
||||
specify a regular expression that matches a line that you would
|
||||
want to appear as the hunk header "TEXT", like this:
|
||||
|
||||
------------------------
|
||||
[diff "tex"]
|
||||
funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$"
|
||||
xfuncname = "^(\\\\(sub)*section\\{.*)$"
|
||||
------------------------
|
||||
|
||||
Note. A single level of backslashes are eaten by the
|
||||
@@ -315,6 +315,8 @@ patterns are available:
|
||||
|
||||
- `java` suitable for source code in the Java language.
|
||||
|
||||
- `objc` suitable for source code in the Objective-C language.
|
||||
|
||||
- `pascal` suitable for source code in the Pascal/Delphi language.
|
||||
|
||||
- `php` suitable for source code in the PHP language.
|
||||
|
||||
@@ -87,12 +87,12 @@ default log message, and before the editor is started.
|
||||
|
||||
It takes one to three parameters. The first is the name of the file
|
||||
that the commit log message. The second is the source of the commit
|
||||
message, and can be: `message` (if a `\-m` or `\-F` option was
|
||||
given); `template` (if a `\-t` option was given or the
|
||||
message, and can be: `message` (if a `-m` or `-F` option was
|
||||
given); `template` (if a `-t` option was given or the
|
||||
configuration option `commit.template` is set); `merge` (if the
|
||||
commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
|
||||
(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
|
||||
a commit SHA1 (if a `\-c`, `\-C` or `\--amend` option was given).
|
||||
a commit SHA1 (if a `-c`, `-C` or `\--amend` option was given).
|
||||
|
||||
If the exit status is non-zero, 'git-commit' will abort.
|
||||
|
||||
@@ -130,6 +130,13 @@ parameter, and is invoked after a commit is made.
|
||||
This hook is meant primarily for notification, and cannot affect
|
||||
the outcome of 'git-commit'.
|
||||
|
||||
pre-rebase
|
||||
----------
|
||||
|
||||
This hook is called by 'git-rebase' and can be used to prevent a branch
|
||||
from getting rebased.
|
||||
|
||||
|
||||
post-checkout
|
||||
-----------
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Functions
|
||||
start_command() followed by finish_command(). Takes a pointer
|
||||
to a `struct child_process` that specifies the details.
|
||||
|
||||
`run_command_v_opt`, `run_command_v_opt_cd`, `run_command_v_opt_cd_env`::
|
||||
`run_command_v_opt`, `run_command_v_opt_cd_env`::
|
||||
|
||||
Convenience functions that encapsulate a sequence of
|
||||
start_command() followed by finish_command(). The argument argv
|
||||
|
||||
9
Makefile
9
Makefile
@@ -294,7 +294,6 @@ PROGRAMS += git-mktag$X
|
||||
PROGRAMS += git-mktree$X
|
||||
PROGRAMS += git-pack-redundant$X
|
||||
PROGRAMS += git-patch-id$X
|
||||
PROGRAMS += git-receive-pack$X
|
||||
PROGRAMS += git-send-pack$X
|
||||
PROGRAMS += git-shell$X
|
||||
PROGRAMS += git-show-index$X
|
||||
@@ -347,6 +346,7 @@ LIB_H += cache.h
|
||||
LIB_H += cache-tree.h
|
||||
LIB_H += commit.h
|
||||
LIB_H += compat/mingw.h
|
||||
LIB_H += compat/cygwin.h
|
||||
LIB_H += csum-file.h
|
||||
LIB_H += decorate.h
|
||||
LIB_H += delta.h
|
||||
@@ -444,6 +444,7 @@ LIB_OBJS += log-tree.o
|
||||
LIB_OBJS += mailmap.o
|
||||
LIB_OBJS += match-trees.o
|
||||
LIB_OBJS += merge-file.o
|
||||
LIB_OBJS += merge-recursive.o
|
||||
LIB_OBJS += name-hash.o
|
||||
LIB_OBJS += object.o
|
||||
LIB_OBJS += pack-check.o
|
||||
@@ -546,6 +547,7 @@ BUILTIN_OBJS += builtin-prune-packed.o
|
||||
BUILTIN_OBJS += builtin-prune.o
|
||||
BUILTIN_OBJS += builtin-push.o
|
||||
BUILTIN_OBJS += builtin-read-tree.o
|
||||
BUILTIN_OBJS += builtin-receive-pack.o
|
||||
BUILTIN_OBJS += builtin-reflog.o
|
||||
BUILTIN_OBJS += builtin-remote.o
|
||||
BUILTIN_OBJS += builtin-rerere.o
|
||||
@@ -647,8 +649,8 @@ ifeq ($(uname_S),SunOS)
|
||||
NO_MEMMEM = YesPlease
|
||||
NO_HSTRERROR = YesPlease
|
||||
NO_MKDTEMP = YesPlease
|
||||
OLD_ICONV = UnfortunatelyYes
|
||||
ifeq ($(uname_R),5.8)
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_UNSETENV = YesPlease
|
||||
NO_SETENV = YesPlease
|
||||
NO_C99_FORMAT = YesPlease
|
||||
@@ -747,6 +749,9 @@ ifeq ($(uname_S),HP-UX)
|
||||
NO_SYS_SELECT_H = YesPlease
|
||||
SNPRINTF_RETURNS_BOGUS = YesPlease
|
||||
endif
|
||||
ifneq (,$(findstring CYGWIN,$(uname_S)))
|
||||
COMPAT_OBJS += compat/cygwin.o
|
||||
endif
|
||||
ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
NO_MMAP = YesPlease
|
||||
NO_PREAD = YesPlease
|
||||
|
||||
13
abspath.c
13
abspath.c
@@ -1,5 +1,16 @@
|
||||
#include "cache.h"
|
||||
|
||||
/*
|
||||
* Do not use this for inspecting *tracked* content. When path is a
|
||||
* symlink to a directory, we do not want to say it is a directory when
|
||||
* dealing with tracked content in the working tree.
|
||||
*/
|
||||
int is_directory(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
return (!stat(path, &st) && S_ISDIR(st.st_mode));
|
||||
}
|
||||
|
||||
/* We allow "recursive" symbolic links. Only within reason, though. */
|
||||
#define MAXDEPTH 5
|
||||
|
||||
@@ -17,7 +28,7 @@ const char *make_absolute_path(const char *path)
|
||||
die ("Too long path: %.*s", 60, path);
|
||||
|
||||
while (depth--) {
|
||||
if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
|
||||
if (!is_directory(buf)) {
|
||||
char *last_slash = strrchr(buf, '/');
|
||||
if (last_slash) {
|
||||
*last_slash = '\0';
|
||||
|
||||
@@ -15,7 +15,7 @@ static char const * const archive_usage[] = {
|
||||
|
||||
#define USES_ZLIB_COMPRESSION 1
|
||||
|
||||
const struct archiver {
|
||||
static const struct archiver {
|
||||
const char *name;
|
||||
write_archive_fn_t write_archive;
|
||||
unsigned int flags;
|
||||
|
||||
16
arm/sha1.c
16
arm/sha1.c
@@ -8,9 +8,9 @@
|
||||
#include <string.h>
|
||||
#include "sha1.h"
|
||||
|
||||
extern void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
|
||||
extern void arm_sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
|
||||
|
||||
void SHA1_Init(SHA_CTX *c)
|
||||
void arm_SHA1_Init(arm_SHA_CTX *c)
|
||||
{
|
||||
c->len = 0;
|
||||
c->hash[0] = 0x67452301;
|
||||
@@ -20,7 +20,7 @@ void SHA1_Init(SHA_CTX *c)
|
||||
c->hash[4] = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n)
|
||||
void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n)
|
||||
{
|
||||
uint32_t workspace[80];
|
||||
unsigned int partial;
|
||||
@@ -32,12 +32,12 @@ void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n)
|
||||
if (partial) {
|
||||
done = 64 - partial;
|
||||
memcpy(c->buffer + partial, p, done);
|
||||
sha_transform(c->hash, c->buffer, workspace);
|
||||
arm_sha_transform(c->hash, c->buffer, workspace);
|
||||
partial = 0;
|
||||
} else
|
||||
done = 0;
|
||||
while (n >= done + 64) {
|
||||
sha_transform(c->hash, p + done, workspace);
|
||||
arm_sha_transform(c->hash, p + done, workspace);
|
||||
done += 64;
|
||||
}
|
||||
} else
|
||||
@@ -46,7 +46,7 @@ void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n)
|
||||
memcpy(c->buffer + partial, p + done, n - done);
|
||||
}
|
||||
|
||||
void SHA1_Final(unsigned char *hash, SHA_CTX *c)
|
||||
void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c)
|
||||
{
|
||||
uint64_t bitlen;
|
||||
uint32_t bitlen_hi, bitlen_lo;
|
||||
@@ -57,7 +57,7 @@ void SHA1_Final(unsigned char *hash, SHA_CTX *c)
|
||||
bitlen = c->len << 3;
|
||||
offset = c->len & 0x3f;
|
||||
padlen = ((offset < 56) ? 56 : (64 + 56)) - offset;
|
||||
SHA1_Update(c, padding, padlen);
|
||||
arm_SHA1_Update(c, padding, padlen);
|
||||
|
||||
bitlen_hi = bitlen >> 32;
|
||||
bitlen_lo = bitlen & 0xffffffff;
|
||||
@@ -69,7 +69,7 @@ void SHA1_Final(unsigned char *hash, SHA_CTX *c)
|
||||
bits[5] = bitlen_lo >> 16;
|
||||
bits[6] = bitlen_lo >> 8;
|
||||
bits[7] = bitlen_lo;
|
||||
SHA1_Update(c, bits, 8);
|
||||
arm_SHA1_Update(c, bits, 8);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
uint32_t v = c->hash[i];
|
||||
|
||||
15
arm/sha1.h
15
arm/sha1.h
@@ -7,12 +7,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct sha_context {
|
||||
typedef struct {
|
||||
uint64_t len;
|
||||
uint32_t hash[5];
|
||||
unsigned char buffer[64];
|
||||
} SHA_CTX;
|
||||
} arm_SHA_CTX;
|
||||
|
||||
void SHA1_Init(SHA_CTX *c);
|
||||
void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n);
|
||||
void SHA1_Final(unsigned char *hash, SHA_CTX *c);
|
||||
void arm_SHA1_Init(arm_SHA_CTX *c);
|
||||
void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n);
|
||||
void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c);
|
||||
|
||||
#define git_SHA_CTX arm_SHA_CTX
|
||||
#define git_SHA1_Init arm_SHA1_Init
|
||||
#define git_SHA1_Update arm_SHA1_Update
|
||||
#define git_SHA1_Final arm_SHA1_Final
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl sha_transform
|
||||
.globl arm_sha_transform
|
||||
|
||||
/*
|
||||
* void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
|
||||
@@ -18,7 +18,7 @@
|
||||
* note: the "data" pointer may be unaligned.
|
||||
*/
|
||||
|
||||
sha_transform:
|
||||
arm_sha_transform:
|
||||
|
||||
stmfd sp!, {r4 - r8, lr}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ static const char ignore_error[] =
|
||||
"The following paths are ignored by one of your .gitignore files:\n";
|
||||
|
||||
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
||||
static int ignore_add_errors, addremove;
|
||||
static int ignore_add_errors, addremove, intent_to_add;
|
||||
|
||||
static struct option builtin_add_options[] = {
|
||||
OPT__DRY_RUN(&show_only),
|
||||
@@ -176,6 +176,7 @@ static struct option builtin_add_options[] = {
|
||||
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
|
||||
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
|
||||
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
|
||||
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
|
||||
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
|
||||
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
||||
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
|
||||
@@ -246,6 +247,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
|
||||
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
|
||||
(show_only ? ADD_CACHE_PRETEND : 0) |
|
||||
(intent_to_add ? ADD_CACHE_INTENT : 0) |
|
||||
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
|
||||
(!(addremove || take_worktree_changes)
|
||||
? ADD_CACHE_IGNORE_REMOVAL : 0));
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "delta.h"
|
||||
#include "builtin.h"
|
||||
#include "string-list.h"
|
||||
#include "dir.h"
|
||||
|
||||
/*
|
||||
* --check turns on checking that the working tree matches the
|
||||
@@ -1696,7 +1697,7 @@ static int match_fragment(struct image *img,
|
||||
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
|
||||
|
||||
/* Try fixing the line in the target */
|
||||
if (sizeof(tgtfixbuf) < tgtlen)
|
||||
if (sizeof(tgtfixbuf) > tgtlen)
|
||||
tgtfix = tgtfixbuf;
|
||||
else
|
||||
tgtfix = xmalloc(tgtlen);
|
||||
@@ -2585,6 +2586,8 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
|
||||
sha1_ptr = sha1;
|
||||
|
||||
ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
|
||||
if (!ce)
|
||||
die("make_cache_entry failed for path '%s'", name);
|
||||
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
|
||||
die ("Could not add %s to temporary index", name);
|
||||
}
|
||||
@@ -2735,15 +2738,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
|
||||
warning("unable to remove submodule %s",
|
||||
patch->old_name);
|
||||
} else if (!unlink(patch->old_name) && rmdir_empty) {
|
||||
char *name = xstrdup(patch->old_name);
|
||||
char *end = strrchr(name, '/');
|
||||
while (end) {
|
||||
*end = 0;
|
||||
if (rmdir(name))
|
||||
break;
|
||||
end = strrchr(name, '/');
|
||||
}
|
||||
free(name);
|
||||
remove_path(patch->old_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2994,29 +2989,45 @@ static int write_out_results(struct patch *list, int skipped_patch)
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
static struct excludes {
|
||||
struct excludes *next;
|
||||
const char *path;
|
||||
} *excludes;
|
||||
static struct string_list limit_by_name;
|
||||
static int has_include;
|
||||
static void add_name_limit(const char *name, int exclude)
|
||||
{
|
||||
struct string_list_item *it;
|
||||
|
||||
it = string_list_append(name, &limit_by_name);
|
||||
it->util = exclude ? NULL : (void *) 1;
|
||||
}
|
||||
|
||||
static int use_patch(struct patch *p)
|
||||
{
|
||||
const char *pathname = p->new_name ? p->new_name : p->old_name;
|
||||
struct excludes *x = excludes;
|
||||
while (x) {
|
||||
if (fnmatch(x->path, pathname, 0) == 0)
|
||||
return 0;
|
||||
x = x->next;
|
||||
}
|
||||
int i;
|
||||
|
||||
/* Paths outside are not touched regardless of "--include" */
|
||||
if (0 < prefix_length) {
|
||||
int pathlen = strlen(pathname);
|
||||
if (pathlen <= prefix_length ||
|
||||
memcmp(prefix, pathname, prefix_length))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
/* See if it matches any of exclude/include rule */
|
||||
for (i = 0; i < limit_by_name.nr; i++) {
|
||||
struct string_list_item *it = &limit_by_name.items[i];
|
||||
if (!fnmatch(it->string, pathname, 0))
|
||||
return (it->util != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we had any include, a path that does not match any rule is
|
||||
* not used. Otherwise, we saw bunch of exclude rules (or none)
|
||||
* and such a path is used.
|
||||
*/
|
||||
return !has_include;
|
||||
}
|
||||
|
||||
|
||||
static void prefix_one(char **name)
|
||||
{
|
||||
char *old_name = *name;
|
||||
@@ -3157,10 +3168,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--exclude=")) {
|
||||
struct excludes *x = xmalloc(sizeof(*x));
|
||||
x->path = arg + 10;
|
||||
x->next = excludes;
|
||||
excludes = x;
|
||||
add_name_limit(arg + 10, 1);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--include=")) {
|
||||
add_name_limit(arg + 10, 0);
|
||||
has_include = 1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "-p")) {
|
||||
|
||||
@@ -1132,6 +1132,8 @@ static int find_copy_in_parent(struct scoreboard *sb,
|
||||
|
||||
if (!DIFF_FILE_VALID(p->one))
|
||||
continue; /* does not exist in parent */
|
||||
if (S_ISGITLINK(p->one->mode))
|
||||
continue; /* ignore git links */
|
||||
if (porigin && !strcmp(p->one->path, porigin->path))
|
||||
/* find_move already dealt with this path */
|
||||
continue;
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "remote.h"
|
||||
#include "blob.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "ll-merge.h"
|
||||
|
||||
static const char * const checkout_usage[] = {
|
||||
"git checkout [options] <branch>",
|
||||
@@ -20,6 +23,18 @@ static const char * const checkout_usage[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct checkout_opts {
|
||||
int quiet;
|
||||
int merge;
|
||||
int force;
|
||||
int writeout_stage;
|
||||
int writeout_error;
|
||||
|
||||
const char *new_branch;
|
||||
int new_branch_log;
|
||||
enum branch_track track;
|
||||
};
|
||||
|
||||
static int post_checkout_hook(struct commit *old, struct commit *new,
|
||||
int changed)
|
||||
{
|
||||
@@ -84,8 +99,121 @@ static int skip_same_name(struct cache_entry *ce, int pos)
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int check_stage(int stage, struct cache_entry *ce, int pos)
|
||||
{
|
||||
while (pos < active_nr &&
|
||||
!strcmp(active_cache[pos]->name, ce->name)) {
|
||||
if (ce_stage(active_cache[pos]) == stage)
|
||||
return 0;
|
||||
pos++;
|
||||
}
|
||||
return error("path '%s' does not have %s version",
|
||||
ce->name,
|
||||
(stage == 2) ? "our" : "their");
|
||||
}
|
||||
|
||||
static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
static int check_all_stages(struct cache_entry *ce, int pos)
|
||||
{
|
||||
if (ce_stage(ce) != 1 ||
|
||||
active_nr <= pos + 2 ||
|
||||
strcmp(active_cache[pos+1]->name, ce->name) ||
|
||||
ce_stage(active_cache[pos+1]) != 2 ||
|
||||
strcmp(active_cache[pos+2]->name, ce->name) ||
|
||||
ce_stage(active_cache[pos+2]) != 3)
|
||||
return error("path '%s' does not have all three versions",
|
||||
ce->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int checkout_stage(int stage, struct cache_entry *ce, int pos,
|
||||
struct checkout *state)
|
||||
{
|
||||
while (pos < active_nr &&
|
||||
!strcmp(active_cache[pos]->name, ce->name)) {
|
||||
if (ce_stage(active_cache[pos]) == stage)
|
||||
return checkout_entry(active_cache[pos], state, NULL);
|
||||
pos++;
|
||||
}
|
||||
return error("path '%s' does not have %s version",
|
||||
ce->name,
|
||||
(stage == 2) ? "our" : "their");
|
||||
}
|
||||
|
||||
/* NEEDSWORK: share with merge-recursive */
|
||||
static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
|
||||
{
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
|
||||
if (!hashcmp(sha1, null_sha1)) {
|
||||
mm->ptr = xstrdup("");
|
||||
mm->size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mm->ptr = read_sha1_file(sha1, &type, &size);
|
||||
if (!mm->ptr || type != OBJ_BLOB)
|
||||
die("unable to read blob object %s", sha1_to_hex(sha1));
|
||||
mm->size = size;
|
||||
}
|
||||
|
||||
static int checkout_merged(int pos, struct checkout *state)
|
||||
{
|
||||
struct cache_entry *ce = active_cache[pos];
|
||||
const char *path = ce->name;
|
||||
mmfile_t ancestor, ours, theirs;
|
||||
int status;
|
||||
unsigned char sha1[20];
|
||||
mmbuffer_t result_buf;
|
||||
|
||||
if (ce_stage(ce) != 1 ||
|
||||
active_nr <= pos + 2 ||
|
||||
strcmp(active_cache[pos+1]->name, path) ||
|
||||
ce_stage(active_cache[pos+1]) != 2 ||
|
||||
strcmp(active_cache[pos+2]->name, path) ||
|
||||
ce_stage(active_cache[pos+2]) != 3)
|
||||
return error("path '%s' does not have all 3 versions", path);
|
||||
|
||||
fill_mm(active_cache[pos]->sha1, &ancestor);
|
||||
fill_mm(active_cache[pos+1]->sha1, &ours);
|
||||
fill_mm(active_cache[pos+2]->sha1, &theirs);
|
||||
|
||||
status = ll_merge(&result_buf, path, &ancestor,
|
||||
&ours, "ours", &theirs, "theirs", 1);
|
||||
free(ancestor.ptr);
|
||||
free(ours.ptr);
|
||||
free(theirs.ptr);
|
||||
if (status < 0 || !result_buf.ptr) {
|
||||
free(result_buf.ptr);
|
||||
return error("path '%s': cannot merge", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* NEEDSWORK:
|
||||
* There is absolutely no reason to write this as a blob object
|
||||
* and create a phoney cache entry just to leak. This hack is
|
||||
* primarily to get to the write_entry() machinery that massages
|
||||
* the contents to work-tree format and writes out which only
|
||||
* allows it for a cache entry. The code in write_entry() needs
|
||||
* to be refactored to allow us to feed a <buffer, size, mode>
|
||||
* instead of a cache entry. Such a refactoring would help
|
||||
* merge_recursive as well (it also writes the merge result to the
|
||||
* object database even when it may contain conflicts).
|
||||
*/
|
||||
if (write_sha1_file(result_buf.ptr, result_buf.size,
|
||||
blob_type, sha1))
|
||||
die("Unable to add merge result for '%s'", path);
|
||||
ce = make_cache_entry(create_ce_mode(active_cache[pos+1]->ce_mode),
|
||||
sha1,
|
||||
path, 2, 0);
|
||||
if (!ce)
|
||||
die("make_cache_entry failed for path '%s'", path);
|
||||
status = checkout_entry(ce, state, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int checkout_paths(struct tree *source_tree, const char **pathspec,
|
||||
struct checkout_opts *opts)
|
||||
{
|
||||
int pos;
|
||||
struct checkout state;
|
||||
@@ -94,7 +222,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
int flag;
|
||||
struct commit *head;
|
||||
int errs = 0;
|
||||
|
||||
int stage = opts->writeout_stage;
|
||||
int merge = opts->merge;
|
||||
int newfd;
|
||||
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
@@ -122,8 +251,16 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
if (pathspec_match(pathspec, NULL, ce->name, 0)) {
|
||||
if (!ce_stage(ce))
|
||||
continue;
|
||||
errs = 1;
|
||||
error("path '%s' is unmerged", ce->name);
|
||||
if (opts->force) {
|
||||
warning("path '%s' is unmerged", ce->name);
|
||||
} else if (stage) {
|
||||
errs |= check_stage(stage, ce, pos);
|
||||
} else if (opts->merge) {
|
||||
errs |= check_all_stages(ce, pos);
|
||||
} else {
|
||||
errs = 1;
|
||||
error("path '%s' is unmerged", ce->name);
|
||||
}
|
||||
pos = skip_same_name(ce, pos) - 1;
|
||||
}
|
||||
}
|
||||
@@ -141,6 +278,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
|
||||
errs |= checkout_entry(ce, &state, NULL);
|
||||
continue;
|
||||
}
|
||||
if (stage)
|
||||
errs |= checkout_stage(stage, ce, pos, &state);
|
||||
else if (merge)
|
||||
errs |= checkout_merged(pos, &state);
|
||||
pos = skip_same_name(ce, pos) - 1;
|
||||
}
|
||||
}
|
||||
@@ -178,17 +319,6 @@ static void describe_detached_head(char *msg, struct commit *commit)
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
struct checkout_opts {
|
||||
int quiet;
|
||||
int merge;
|
||||
int force;
|
||||
int writeout_error;
|
||||
|
||||
const char *new_branch;
|
||||
int new_branch_log;
|
||||
enum branch_track track;
|
||||
};
|
||||
|
||||
static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
|
||||
{
|
||||
struct unpack_trees_options opts;
|
||||
@@ -293,6 +423,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
*/
|
||||
struct tree *result;
|
||||
struct tree *work;
|
||||
struct merge_options o;
|
||||
if (!opts->merge)
|
||||
return 1;
|
||||
parse_commit(old->commit);
|
||||
@@ -311,13 +442,17 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
*/
|
||||
|
||||
add_files_to_cache(NULL, NULL, 0);
|
||||
work = write_tree_from_memory();
|
||||
init_merge_options(&o);
|
||||
o.verbosity = 0;
|
||||
work = write_tree_from_memory(&o);
|
||||
|
||||
ret = reset_tree(new->commit->tree, opts, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
merge_trees(new->commit->tree, work, old->commit->tree,
|
||||
new->name, "local", &result);
|
||||
o.branch1 = new->name;
|
||||
o.branch2 = "local";
|
||||
merge_trees(&o, new->commit->tree, work,
|
||||
old->commit->tree, &result);
|
||||
ret = reset_tree(new->commit->tree, opts, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -328,7 +463,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
commit_locked_index(lock_file))
|
||||
die("unable to write new index file");
|
||||
|
||||
if (!opts->force)
|
||||
if (!opts->force && !opts->quiet)
|
||||
show_local_changes(&new->commit->object);
|
||||
|
||||
return 0;
|
||||
@@ -440,6 +575,11 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||
return ret || opts->writeout_error;
|
||||
}
|
||||
|
||||
static int git_checkout_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
return git_xmerge_config(var, value, cb);
|
||||
}
|
||||
|
||||
int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct checkout_opts opts;
|
||||
@@ -447,14 +587,21 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
const char *arg;
|
||||
struct branch_info new;
|
||||
struct tree *source_tree = NULL;
|
||||
char *conflict_style = NULL;
|
||||
struct option options[] = {
|
||||
OPT__QUIET(&opts.quiet),
|
||||
OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
|
||||
OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
|
||||
OPT_SET_INT('t', "track", &opts.track, "track",
|
||||
BRANCH_TRACK_EXPLICIT),
|
||||
OPT_SET_INT('2', "ours", &opts.writeout_stage, "stage",
|
||||
2),
|
||||
OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
|
||||
3),
|
||||
OPT_BOOLEAN('f', NULL, &opts.force, "force"),
|
||||
OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
|
||||
OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
|
||||
OPT_STRING(0, "conflict", &conflict_style, "style",
|
||||
"conflict style (merge or diff3)"),
|
||||
OPT_END(),
|
||||
};
|
||||
int has_dash_dash;
|
||||
@@ -462,7 +609,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
memset(&new, 0, sizeof(new));
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
git_config(git_checkout_config, NULL);
|
||||
|
||||
opts.track = BRANCH_TRACK_UNSPECIFIED;
|
||||
|
||||
@@ -486,6 +633,13 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (opts.track == BRANCH_TRACK_UNSPECIFIED)
|
||||
opts.track = git_branch_track;
|
||||
if (conflict_style) {
|
||||
opts.merge = 1; /* implied */
|
||||
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
|
||||
}
|
||||
|
||||
if (!opts.new_branch && (opts.track != git_branch_track))
|
||||
die("git checkout: --track and --no-track require -b");
|
||||
|
||||
if (opts.force && opts.merge)
|
||||
die("git checkout: -f and -m are incompatible");
|
||||
@@ -569,15 +723,18 @@ no_reference:
|
||||
die("invalid path specification");
|
||||
|
||||
/* Checkout paths */
|
||||
if (opts.new_branch || opts.force || opts.merge) {
|
||||
if (opts.new_branch) {
|
||||
if (argc == 1) {
|
||||
die("git checkout: updating paths is incompatible with switching branches/forcing\nDid you intend to checkout '%s' which can not be resolved as commit?", argv[0]);
|
||||
die("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?", argv[0]);
|
||||
} else {
|
||||
die("git checkout: updating paths is incompatible with switching branches/forcing");
|
||||
die("git checkout: updating paths is incompatible with switching branches.");
|
||||
}
|
||||
}
|
||||
|
||||
return checkout_paths(source_tree, pathspec);
|
||||
if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
|
||||
die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.");
|
||||
|
||||
return checkout_paths(source_tree, pathspec, &opts);
|
||||
}
|
||||
|
||||
if (opts.new_branch) {
|
||||
@@ -595,6 +752,8 @@ no_reference:
|
||||
if (new.name && !new.commit) {
|
||||
die("Cannot switch branch to a non-commit.");
|
||||
}
|
||||
if (opts.writeout_stage)
|
||||
die("--ours/--theirs is incompatible with switching branches.");
|
||||
|
||||
return switch_branches(&opts, &new);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
|
||||
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
|
||||
const char *path;
|
||||
path = mkpath("%s%s", repo, suffix[i]);
|
||||
if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
|
||||
if (is_directory(path)) {
|
||||
*is_bundle = 0;
|
||||
return xstrdup(make_nonrelative_path(path));
|
||||
}
|
||||
@@ -140,13 +140,6 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
|
||||
return xstrndup(start, end - start);
|
||||
}
|
||||
|
||||
static int is_directory(const char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
return !stat(path, &buf) && S_ISDIR(buf.st_mode);
|
||||
}
|
||||
|
||||
static void strip_trailing_slashes(char *dir)
|
||||
{
|
||||
char *end = dir + strlen(dir);
|
||||
|
||||
@@ -46,7 +46,8 @@ static const char commit_utf8_warn[] =
|
||||
"variable i18n.commitencoding to the encoding your project uses.\n";
|
||||
|
||||
int commit_tree(const char *msg, unsigned char *tree,
|
||||
struct commit_list *parents, unsigned char *ret)
|
||||
struct commit_list *parents, unsigned char *ret,
|
||||
const char *author)
|
||||
{
|
||||
int result;
|
||||
int encoding_is_utf8;
|
||||
@@ -74,7 +75,9 @@ int commit_tree(const char *msg, unsigned char *tree,
|
||||
}
|
||||
|
||||
/* Person/date information */
|
||||
strbuf_addf(&buffer, "author %s\n", git_author_info(IDENT_ERROR_ON_NO_NAME));
|
||||
if (!author)
|
||||
author = git_author_info(IDENT_ERROR_ON_NO_NAME);
|
||||
strbuf_addf(&buffer, "author %s\n", author);
|
||||
strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
|
||||
if (!encoding_is_utf8)
|
||||
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
|
||||
@@ -123,7 +126,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
if (strbuf_read(&buffer, 0, 0) < 0)
|
||||
die("git commit-tree: read returned %s", strerror(errno));
|
||||
|
||||
if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1)) {
|
||||
if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
|
||||
printf("%s\n", sha1_to_hex(commit_sha1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
|
||||
active_cache_tree = cache_tree();
|
||||
if (cache_tree_update(active_cache_tree,
|
||||
active_cache, active_nr, 0, 0) < 0) {
|
||||
error("Error building trees");
|
||||
error("Error building trees; the index is unmerged?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -667,14 +667,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out if the message starting at position 'start' in the strbuf
|
||||
* contains only whitespace and Signed-off-by lines.
|
||||
* Find out if the message in the strbuf contains only whitespace and
|
||||
* Signed-off-by lines.
|
||||
*/
|
||||
static int message_is_empty(struct strbuf *sb, int start)
|
||||
static int message_is_empty(struct strbuf *sb)
|
||||
{
|
||||
struct strbuf tmpl;
|
||||
const char *nl;
|
||||
int eol, i;
|
||||
int eol, i, start = 0;
|
||||
|
||||
if (cleanup_mode == CLEANUP_NONE && sb->len)
|
||||
return 0;
|
||||
@@ -929,34 +929,14 @@ static const char commit_utf8_warn[] =
|
||||
"You may want to amend it after fixing the message, or set the config\n"
|
||||
"variable i18n.commitencoding to the encoding your project uses.\n";
|
||||
|
||||
static void add_parent(struct strbuf *sb, const unsigned char *sha1)
|
||||
{
|
||||
struct object *obj = parse_object(sha1);
|
||||
const char *parent = sha1_to_hex(sha1);
|
||||
const char *cp;
|
||||
|
||||
if (!obj)
|
||||
die("Unable to find commit parent %s", parent);
|
||||
if (obj->type != OBJ_COMMIT)
|
||||
die("Parent %s isn't a proper commit", parent);
|
||||
|
||||
for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) {
|
||||
if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') {
|
||||
error("duplicate parent %s ignored", parent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
strbuf_addf(sb, "parent %s\n", parent);
|
||||
}
|
||||
|
||||
int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int header_len;
|
||||
struct strbuf sb;
|
||||
const char *index_file, *reflog_msg;
|
||||
char *nl, *p;
|
||||
unsigned char commit_sha1[20];
|
||||
struct ref_lock *ref_lock;
|
||||
struct commit_list *parents = NULL, **pptr = &parents;
|
||||
|
||||
git_config(git_commit_config, NULL);
|
||||
|
||||
@@ -971,13 +951,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The commit object
|
||||
*/
|
||||
strbuf_init(&sb, 0);
|
||||
strbuf_addf(&sb, "tree %s\n",
|
||||
sha1_to_hex(active_cache_tree->sha1));
|
||||
|
||||
/* Determine parents */
|
||||
if (initial_commit) {
|
||||
reflog_msg = "commit (initial)";
|
||||
@@ -991,13 +964,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
die("could not parse HEAD commit");
|
||||
|
||||
for (c = commit->parents; c; c = c->next)
|
||||
add_parent(&sb, c->item->object.sha1);
|
||||
pptr = &commit_list_insert(c->item, pptr)->next;
|
||||
} else if (in_merge) {
|
||||
struct strbuf m;
|
||||
FILE *fp;
|
||||
|
||||
reflog_msg = "commit (merge)";
|
||||
add_parent(&sb, head_sha1);
|
||||
pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
|
||||
strbuf_init(&m, 0);
|
||||
fp = fopen(git_path("MERGE_HEAD"), "r");
|
||||
if (fp == NULL)
|
||||
@@ -1007,24 +980,18 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
unsigned char sha1[20];
|
||||
if (get_sha1_hex(m.buf, sha1) < 0)
|
||||
die("Corrupt MERGE_HEAD file (%s)", m.buf);
|
||||
add_parent(&sb, sha1);
|
||||
pptr = &commit_list_insert(lookup_commit(sha1), pptr)->next;
|
||||
}
|
||||
fclose(fp);
|
||||
strbuf_release(&m);
|
||||
} else {
|
||||
reflog_msg = "commit";
|
||||
strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
|
||||
pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
|
||||
}
|
||||
|
||||
strbuf_addf(&sb, "author %s\n",
|
||||
fmt_ident(author_name, author_email, author_date, IDENT_ERROR_ON_NO_NAME));
|
||||
strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
|
||||
if (!is_encoding_utf8(git_commit_encoding))
|
||||
strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
|
||||
strbuf_addch(&sb, '\n');
|
||||
parents = reduce_heads(parents);
|
||||
|
||||
/* Finally, get the commit message */
|
||||
header_len = sb.len;
|
||||
strbuf_init(&sb, 0);
|
||||
if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
|
||||
rollback_index_files();
|
||||
die("could not read commit message");
|
||||
@@ -1037,16 +1004,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (cleanup_mode != CLEANUP_NONE)
|
||||
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
|
||||
if (sb.len < header_len || message_is_empty(&sb, header_len)) {
|
||||
if (message_is_empty(&sb)) {
|
||||
rollback_index_files();
|
||||
fprintf(stderr, "Aborting commit due to empty commit message.\n");
|
||||
exit(1);
|
||||
}
|
||||
strbuf_addch(&sb, '\0');
|
||||
if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
|
||||
fprintf(stderr, commit_utf8_warn);
|
||||
|
||||
if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) {
|
||||
if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1,
|
||||
fmt_ident(author_name, author_email, author_date,
|
||||
IDENT_ERROR_ON_NO_NAME))) {
|
||||
rollback_index_files();
|
||||
die("failed to write commit object");
|
||||
}
|
||||
@@ -1055,12 +1021,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
initial_commit ? NULL : head_sha1,
|
||||
0);
|
||||
|
||||
nl = strchr(sb.buf + header_len, '\n');
|
||||
nl = strchr(sb.buf, '\n');
|
||||
if (nl)
|
||||
strbuf_setlen(&sb, nl + 1 - sb.buf);
|
||||
else
|
||||
strbuf_addch(&sb, '\n');
|
||||
strbuf_remove(&sb, 0, header_len);
|
||||
strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
|
||||
strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
|
||||
|
||||
|
||||
@@ -735,7 +735,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
|
||||
conn = git_connect(fd, (char *)dest, args.uploadpack,
|
||||
args.verbose ? CONNECT_VERBOSE : 0);
|
||||
if (conn) {
|
||||
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
||||
get_remote_heads(fd[0], &ref, 0, NULL, 0, NULL);
|
||||
|
||||
ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
|
||||
close(fd[0]);
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
#include "revision.h"
|
||||
#include "tag.h"
|
||||
|
||||
static const char *fmt_merge_msg_usage =
|
||||
"git fmt-merge-msg [--log] [--no-log] [--file <file>]";
|
||||
static const char * const fmt_merge_msg_usage[] = {
|
||||
"git fmt-merge-msg [--log|--no-log] [--file <file>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int merge_summary;
|
||||
|
||||
@@ -347,38 +349,29 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
|
||||
|
||||
int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *inpath = NULL;
|
||||
struct option options[] = {
|
||||
OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
|
||||
OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
|
||||
OPT_STRING('F', "file", &inpath, "file", "file to read from"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
FILE *in = stdin;
|
||||
struct strbuf input, output;
|
||||
int ret;
|
||||
|
||||
git_config(fmt_merge_msg_config, NULL);
|
||||
argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
|
||||
if (argc > 0)
|
||||
usage_with_options(fmt_merge_msg_usage, options);
|
||||
|
||||
while (argc > 1) {
|
||||
if (!strcmp(argv[1], "--log") || !strcmp(argv[1], "--summary"))
|
||||
merge_summary = 1;
|
||||
else if (!strcmp(argv[1], "--no-log")
|
||||
|| !strcmp(argv[1], "--no-summary"))
|
||||
merge_summary = 0;
|
||||
else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
|
||||
if (argc < 3)
|
||||
die ("Which file?");
|
||||
if (!strcmp(argv[2], "-"))
|
||||
in = stdin;
|
||||
else {
|
||||
fclose(in);
|
||||
in = fopen(argv[2], "r");
|
||||
if (!in)
|
||||
die("cannot open %s", argv[2]);
|
||||
}
|
||||
argc--; argv++;
|
||||
} else
|
||||
break;
|
||||
argc--; argv++;
|
||||
if (inpath && strcmp(inpath, "-")) {
|
||||
in = fopen(inpath, "r");
|
||||
if (!in)
|
||||
die("cannot open %s", inpath);
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
usage(fmt_merge_msg_usage);
|
||||
|
||||
strbuf_init(&input, 0);
|
||||
if (strbuf_read(&input, fileno(in), 0) < 0)
|
||||
die("could not read input file %s", strerror(errno));
|
||||
@@ -387,6 +380,6 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
ret = fmt_merge_msg(merge_summary, &input, &output);
|
||||
if (ret)
|
||||
return ret;
|
||||
printf("%s", output.buf);
|
||||
write_in_full(STDOUT_FILENO, output.buf, output.len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -320,9 +320,7 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un
|
||||
|
||||
static const char *copy_line(const char *buf)
|
||||
{
|
||||
const char *eol = strchr(buf, '\n');
|
||||
if (!eol)
|
||||
return "";
|
||||
const char *eol = strchrnul(buf, '\n');
|
||||
return xmemdupz(buf, eol - buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ static int pack_refs = 1;
|
||||
static int aggressive_window = -1;
|
||||
static int gc_auto_threshold = 6700;
|
||||
static int gc_auto_pack_limit = 50;
|
||||
static char *prune_expire = "2.weeks.ago";
|
||||
static const char *prune_expire = "2.weeks.ago";
|
||||
|
||||
#define MAX_ADD 10
|
||||
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
|
||||
@@ -57,15 +57,12 @@ static int gc_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "gc.pruneexpire")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
if (strcmp(value, "now")) {
|
||||
if (value && strcmp(value, "now")) {
|
||||
unsigned long now = approxidate("now");
|
||||
if (approxidate(value) >= now)
|
||||
return error("Invalid %s: '%s'", var, value);
|
||||
}
|
||||
prune_expire = xstrdup(value);
|
||||
return 0;
|
||||
return git_config_string(&prune_expire, var, value);
|
||||
}
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
@@ -295,6 +295,9 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||
push_arg("-l");
|
||||
if (opt->unmatch_name_only)
|
||||
push_arg("-L");
|
||||
if (opt->null_following_name)
|
||||
/* in GNU grep git's "-z" translates to "-Z" */
|
||||
push_arg("-Z");
|
||||
if (opt->count)
|
||||
push_arg("-c");
|
||||
if (opt->post_context || opt->pre_context) {
|
||||
@@ -599,6 +602,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
opt.unmatch_name_only = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-z", arg) ||
|
||||
!strcmp("--null", arg)) {
|
||||
opt.null_following_name = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-c", arg) ||
|
||||
!strcmp("--count", arg)) {
|
||||
opt.count = 1;
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#define TEST_FILEMODE 1
|
||||
#endif
|
||||
|
||||
static int init_is_bare_repository = 0;
|
||||
static int init_shared_repository = -1;
|
||||
|
||||
static void safe_create_dir(const char *dir, int share)
|
||||
{
|
||||
if (mkdir(dir, 0777) < 0) {
|
||||
@@ -191,6 +194,9 @@ static int create_default_files(const char *template_path)
|
||||
copy_templates(template_path);
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
is_bare_repository_cfg = init_is_bare_repository;
|
||||
if (init_shared_repository != -1)
|
||||
shared_repository = init_shared_repository;
|
||||
|
||||
/*
|
||||
* We would have created the above under user's umask -- under
|
||||
@@ -277,6 +283,8 @@ int init_db(const char *template_dir, unsigned int flags)
|
||||
|
||||
safe_create_dir(get_git_dir(), 0);
|
||||
|
||||
init_is_bare_repository = is_bare_repository();
|
||||
|
||||
/* Check to see if the repository version is right.
|
||||
* Note that a newly created repository does not have
|
||||
* config file, so this will not fail. What we are catching
|
||||
@@ -381,9 +389,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
|
||||
sizeof(git_dir)), 0);
|
||||
} else if (!strcmp(arg, "--shared"))
|
||||
shared_repository = PERM_GROUP;
|
||||
init_shared_repository = PERM_GROUP;
|
||||
else if (!prefixcmp(arg, "--shared="))
|
||||
shared_repository = git_config_perm("arg", arg+9);
|
||||
init_shared_repository = git_config_perm("arg", arg+9);
|
||||
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
|
||||
flags |= INIT_DB_QUIET;
|
||||
else
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
|
||||
{
|
||||
@@ -21,8 +22,10 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char merge_base_usage[] =
|
||||
"git merge-base [--all] <commit-id> <commit-id>...";
|
||||
static const char * const merge_base_usage[] = {
|
||||
"git merge-base [--all] <commit-id> <commit-id>...",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct commit *get_commit_reference(const char *arg)
|
||||
{
|
||||
@@ -44,25 +47,17 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
|
||||
int rev_nr = 0;
|
||||
int show_all = 0;
|
||||
|
||||
struct option options[] = {
|
||||
OPT_BOOLEAN('a', "all", &show_all, "outputs all common ancestors"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
while (1 < argc && argv[1][0] == '-') {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "-a") || !strcmp(arg, "--all"))
|
||||
show_all = 1;
|
||||
else
|
||||
usage(merge_base_usage);
|
||||
argc--; argv++;
|
||||
}
|
||||
if (argc < 3)
|
||||
usage(merge_base_usage);
|
||||
|
||||
rev = xmalloc((argc - 1) * sizeof(*rev));
|
||||
|
||||
do {
|
||||
rev[rev_nr++] = get_commit_reference(argv[1]);
|
||||
argc--; argv++;
|
||||
} while (argc > 1);
|
||||
|
||||
argc = parse_options(argc, argv, options, merge_base_usage, 0);
|
||||
if (argc < 2)
|
||||
usage_with_options(merge_base_usage, options);
|
||||
rev = xmalloc(argc * sizeof(*rev));
|
||||
while (argc-- > 0)
|
||||
rev[rev_nr++] = get_commit_reference(*argv++);
|
||||
return show_merge_base(rev, rev_nr, show_all);
|
||||
}
|
||||
|
||||
@@ -2,57 +2,76 @@
|
||||
#include "cache.h"
|
||||
#include "xdiff/xdiff.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char merge_file_usage[] =
|
||||
"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
|
||||
static const char *const merge_file_usage[] = {
|
||||
"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int label_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
static int label_count = 0;
|
||||
const char **names = (const char **)opt->value;
|
||||
|
||||
if (label_count >= 3)
|
||||
return error("too many labels on the command line");
|
||||
names[label_count++] = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *names[3];
|
||||
const char *names[3] = { NULL, NULL, NULL };
|
||||
mmfile_t mmfs[3];
|
||||
mmbuffer_t result = {NULL, 0};
|
||||
xpparam_t xpp = {XDF_NEED_MINIMAL};
|
||||
int ret = 0, i = 0, to_stdout = 0;
|
||||
int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
|
||||
int merge_style = 0, quiet = 0;
|
||||
int nongit;
|
||||
|
||||
while (argc > 4) {
|
||||
if (!strcmp(argv[1], "-L") && i < 3) {
|
||||
names[i++] = argv[2];
|
||||
argc--;
|
||||
argv++;
|
||||
} else if (!strcmp(argv[1], "-p") ||
|
||||
!strcmp(argv[1], "--stdout"))
|
||||
to_stdout = 1;
|
||||
else if (!strcmp(argv[1], "-q") ||
|
||||
!strcmp(argv[1], "--quiet"))
|
||||
freopen("/dev/null", "w", stderr);
|
||||
else
|
||||
usage(merge_file_usage);
|
||||
argc--;
|
||||
argv++;
|
||||
struct option options[] = {
|
||||
OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
|
||||
OPT_SET_INT(0, "diff3", &merge_style, "use a diff3 based merge", XDL_MERGE_DIFF3),
|
||||
OPT__QUIET(&quiet),
|
||||
OPT_CALLBACK('L', NULL, names, "name",
|
||||
"set labels for file1/orig_file/file2", &label_cb),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
prefix = setup_git_directory_gently(&nongit);
|
||||
if (!nongit) {
|
||||
/* Read the configuration file */
|
||||
git_config(git_xmerge_config, NULL);
|
||||
if (0 <= git_xmerge_style)
|
||||
merge_style = git_xmerge_style;
|
||||
}
|
||||
|
||||
if (argc != 4)
|
||||
usage(merge_file_usage);
|
||||
|
||||
for (; i < 3; i++)
|
||||
names[i] = argv[i + 1];
|
||||
argc = parse_options(argc, argv, options, merge_file_usage, 0);
|
||||
if (argc != 3)
|
||||
usage_with_options(merge_file_usage, options);
|
||||
if (quiet)
|
||||
freopen("/dev/null", "w", stderr);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (read_mmfile(mmfs + i, argv[i + 1]))
|
||||
if (!names[i])
|
||||
names[i] = argv[i];
|
||||
if (read_mmfile(mmfs + i, argv[i]))
|
||||
return -1;
|
||||
if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
|
||||
return error("Cannot merge binary files: %s\n",
|
||||
argv[i + 1]);
|
||||
argv[i]);
|
||||
}
|
||||
|
||||
ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
|
||||
&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);
|
||||
&xpp, merge_level | merge_style, &result);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
free(mmfs[i].ptr);
|
||||
|
||||
if (ret >= 0) {
|
||||
const char *filename = argv[1];
|
||||
const char *filename = argv[0];
|
||||
FILE *f = to_stdout ? stdout : fopen(filename, "wb");
|
||||
|
||||
if (!f)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
116
builtin-merge.c
116
builtin-merge.c
@@ -23,6 +23,7 @@
|
||||
#include "color.h"
|
||||
#include "rerere.h"
|
||||
#include "help.h"
|
||||
#include "merge-recursive.h"
|
||||
|
||||
#define DEFAULT_TWOHEAD (1<<0)
|
||||
#define DEFAULT_OCTOPUS (1<<1)
|
||||
@@ -122,8 +123,7 @@ static struct strategy *get_strategy(const char *name)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = xmalloc(sizeof(struct strategy));
|
||||
memset(ret, 0, sizeof(struct strategy));
|
||||
ret = xcalloc(1, sizeof(struct strategy));
|
||||
ret->name = xstrdup(name);
|
||||
return ret;
|
||||
}
|
||||
@@ -476,6 +476,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
|
||||
|
||||
buf = xstrdup(v);
|
||||
argc = split_cmdline(buf, &argv);
|
||||
if (argc < 0)
|
||||
die("Bad branch.%s.mergeoptions string", branch);
|
||||
argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
|
||||
memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
|
||||
argc++;
|
||||
@@ -544,29 +546,76 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
|
||||
int i = 0, ret;
|
||||
struct commit_list *j;
|
||||
struct strbuf buf;
|
||||
int index_fd;
|
||||
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
args = xmalloc((4 + commit_list_count(common) +
|
||||
commit_list_count(remoteheads)) * sizeof(char *));
|
||||
strbuf_init(&buf, 0);
|
||||
strbuf_addf(&buf, "merge-%s", strategy);
|
||||
args[i++] = buf.buf;
|
||||
for (j = common; j; j = j->next)
|
||||
args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
|
||||
args[i++] = "--";
|
||||
args[i++] = head_arg;
|
||||
for (j = remoteheads; j; j = j->next)
|
||||
args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
|
||||
args[i] = NULL;
|
||||
ret = run_command_v_opt(args, RUN_GIT_CMD);
|
||||
strbuf_release(&buf);
|
||||
i = 1;
|
||||
for (j = common; j; j = j->next)
|
||||
free((void *)args[i++]);
|
||||
i += 2;
|
||||
for (j = remoteheads; j; j = j->next)
|
||||
free((void *)args[i++]);
|
||||
free(args);
|
||||
return -ret;
|
||||
index_fd = hold_locked_index(lock, 1);
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
if (active_cache_changed &&
|
||||
(write_cache(index_fd, active_cache, active_nr) ||
|
||||
commit_locked_index(lock)))
|
||||
return error("Unable to write index.");
|
||||
rollback_lock_file(lock);
|
||||
|
||||
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
|
||||
int clean;
|
||||
struct commit *result;
|
||||
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
|
||||
int index_fd;
|
||||
struct commit_list *reversed = NULL;
|
||||
struct merge_options o;
|
||||
|
||||
if (remoteheads->next) {
|
||||
error("Not handling anything other than two heads merge.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
init_merge_options(&o);
|
||||
if (!strcmp(strategy, "subtree"))
|
||||
o.subtree_merge = 1;
|
||||
|
||||
o.branch1 = head_arg;
|
||||
o.branch2 = remoteheads->item->util;
|
||||
|
||||
for (j = common; j; j = j->next)
|
||||
commit_list_insert(j->item, &reversed);
|
||||
|
||||
index_fd = hold_locked_index(lock, 1);
|
||||
clean = merge_recursive(&o, lookup_commit(head),
|
||||
remoteheads->item, reversed, &result);
|
||||
if (active_cache_changed &&
|
||||
(write_cache(index_fd, active_cache, active_nr) ||
|
||||
commit_locked_index(lock)))
|
||||
die ("unable to write %s", get_index_file());
|
||||
rollback_lock_file(lock);
|
||||
return clean ? 0 : 1;
|
||||
} else {
|
||||
args = xmalloc((4 + commit_list_count(common) +
|
||||
commit_list_count(remoteheads)) * sizeof(char *));
|
||||
strbuf_init(&buf, 0);
|
||||
strbuf_addf(&buf, "merge-%s", strategy);
|
||||
args[i++] = buf.buf;
|
||||
for (j = common; j; j = j->next)
|
||||
args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
|
||||
args[i++] = "--";
|
||||
args[i++] = head_arg;
|
||||
for (j = remoteheads; j; j = j->next)
|
||||
args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
|
||||
args[i] = NULL;
|
||||
ret = run_command_v_opt(args, RUN_GIT_CMD);
|
||||
strbuf_release(&buf);
|
||||
i = 1;
|
||||
for (j = common; j; j = j->next)
|
||||
free((void *)args[i++]);
|
||||
i += 2;
|
||||
for (j = remoteheads; j; j = j->next)
|
||||
free((void *)args[i++]);
|
||||
free(args);
|
||||
discard_cache();
|
||||
if (read_cache() < 0)
|
||||
die("failed to read the cache");
|
||||
return -ret;
|
||||
}
|
||||
}
|
||||
|
||||
static void count_diff_files(struct diff_queue_struct *q,
|
||||
@@ -683,15 +732,15 @@ static void add_strategies(const char *string, unsigned attr)
|
||||
static int merge_trivial(void)
|
||||
{
|
||||
unsigned char result_tree[20], result_commit[20];
|
||||
struct commit_list *parent = xmalloc(sizeof(struct commit_list *));
|
||||
struct commit_list *parent = xmalloc(sizeof(*parent));
|
||||
|
||||
write_tree_trivial(result_tree);
|
||||
printf("Wonderful.\n");
|
||||
parent->item = lookup_commit(head);
|
||||
parent->next = xmalloc(sizeof(struct commit_list *));
|
||||
parent->next = xmalloc(sizeof(*parent->next));
|
||||
parent->next->item = remoteheads->item;
|
||||
parent->next->next = NULL;
|
||||
commit_tree(merge_msg.buf, result_tree, parent, result_commit);
|
||||
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
|
||||
finish(result_commit, "In-index merge");
|
||||
drop_save();
|
||||
return 0;
|
||||
@@ -720,7 +769,7 @@ static int finish_automerge(struct commit_list *common,
|
||||
}
|
||||
free_commit_list(remoteheads);
|
||||
strbuf_addch(&merge_msg, '\n');
|
||||
commit_tree(merge_msg.buf, result_tree, parents, result_commit);
|
||||
commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
|
||||
strbuf_addf(&buf, "Merge made by %s.", wt_strategy);
|
||||
finish(result_commit, buf.buf);
|
||||
strbuf_release(&buf);
|
||||
@@ -777,10 +826,6 @@ static int evaluate_result(void)
|
||||
int cnt = 0;
|
||||
struct rev_info rev;
|
||||
|
||||
discard_cache();
|
||||
if (read_cache() < 0)
|
||||
die("failed to read the cache");
|
||||
|
||||
/* Check how many files differ. */
|
||||
init_revisions(&rev, "");
|
||||
setup_revisions(0, NULL, &rev, NULL);
|
||||
@@ -914,12 +959,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
struct object *o;
|
||||
struct commit *commit;
|
||||
|
||||
o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT);
|
||||
if (!o)
|
||||
die("%s - not something we can merge", argv[i]);
|
||||
remotes = &commit_list_insert(lookup_commit(o->sha1),
|
||||
remotes)->next;
|
||||
commit = lookup_commit(o->sha1);
|
||||
commit->util = (void *)argv[i];
|
||||
remotes = &commit_list_insert(commit, remotes)->next;
|
||||
|
||||
strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
|
||||
setenv(buf.buf, argv[i], 1);
|
||||
@@ -1113,7 +1160,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
/* Automerge succeeded. */
|
||||
discard_cache();
|
||||
write_tree_trivial(result_tree);
|
||||
automerge_was_ok = 1;
|
||||
break;
|
||||
|
||||
@@ -465,7 +465,7 @@ static void write_pack_file(void)
|
||||
char tmpname[PATH_MAX];
|
||||
int fd;
|
||||
snprintf(tmpname, sizeof(tmpname),
|
||||
"%s/tmp_pack_XXXXXX", get_object_directory());
|
||||
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
|
||||
fd = xmkstemp(tmpname);
|
||||
pack_tmp_name = xstrdup(tmpname);
|
||||
f = sha1fd(fd, pack_tmp_name);
|
||||
@@ -1369,12 +1369,10 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
|
||||
int window, int depth, unsigned *processed)
|
||||
{
|
||||
uint32_t i, idx = 0, count = 0;
|
||||
unsigned int array_size = window * sizeof(struct unpacked);
|
||||
struct unpacked *array;
|
||||
unsigned long mem_usage = 0;
|
||||
|
||||
array = xmalloc(array_size);
|
||||
memset(array, 0, array_size);
|
||||
array = xcalloc(window, sizeof(struct unpacked));
|
||||
|
||||
for (;;) {
|
||||
struct object_entry *entry = *list++;
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char * const prune_usage[] = {
|
||||
"git prune [-n] [--expire <time>] [--] [<head>...]",
|
||||
"git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
|
||||
NULL
|
||||
};
|
||||
static int show_only;
|
||||
static int verbose;
|
||||
static unsigned long expire;
|
||||
|
||||
static int prune_tmp_object(char *path, const char *filename)
|
||||
static int prune_tmp_object(const char *path, const char *filename)
|
||||
{
|
||||
const char *fullpath = mkpath("%s/%s", path, filename);
|
||||
if (expire) {
|
||||
@@ -39,11 +40,12 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
|
||||
if (st.st_mtime > expire)
|
||||
return 0;
|
||||
}
|
||||
if (show_only) {
|
||||
if (show_only || verbose) {
|
||||
enum object_type type = sha1_object_info(sha1, NULL);
|
||||
printf("%s %s\n", sha1_to_hex(sha1),
|
||||
(type > 0) ? typename(type) : "unknown");
|
||||
} else
|
||||
}
|
||||
if (!show_only)
|
||||
unlink(fullpath);
|
||||
return 0;
|
||||
}
|
||||
@@ -110,24 +112,22 @@ static void prune_object_dir(const char *path)
|
||||
/*
|
||||
* Write errors (particularly out of space) can result in
|
||||
* failed temporary packs (and more rarely indexes and other
|
||||
* files begining with "tmp_") accumulating in the
|
||||
* object directory.
|
||||
* files begining with "tmp_") accumulating in the object
|
||||
* and the pack directories.
|
||||
*/
|
||||
static void remove_temporary_files(void)
|
||||
static void remove_temporary_files(const char *path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
char* dirname=get_object_directory();
|
||||
|
||||
dir = opendir(dirname);
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
fprintf(stderr, "Unable to open object directory %s\n",
|
||||
dirname);
|
||||
fprintf(stderr, "Unable to open directory %s\n", path);
|
||||
return;
|
||||
}
|
||||
while ((de = readdir(dir)) != NULL)
|
||||
if (!prefixcmp(de->d_name, "tmp_"))
|
||||
prune_tmp_object(dirname, de->d_name);
|
||||
prune_tmp_object(path, de->d_name);
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
@@ -137,10 +137,13 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('n', NULL, &show_only,
|
||||
"do not remove, show only"),
|
||||
OPT_BOOLEAN('v', NULL, &verbose,
|
||||
"report pruned objects"),
|
||||
OPT_DATE(0, "expire", &expire,
|
||||
"expire objects older than <time>"),
|
||||
OPT_END()
|
||||
};
|
||||
char *s;
|
||||
|
||||
save_commit_buffer = 0;
|
||||
init_revisions(&revs, prefix);
|
||||
@@ -163,6 +166,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
prune_object_dir(get_object_directory());
|
||||
|
||||
prune_packed_objects(show_only);
|
||||
remove_temporary_files();
|
||||
remove_temporary_files(get_object_directory());
|
||||
s = xstrdup(mkpath("%s/pack", get_object_directory()));
|
||||
remove_temporary_files(s);
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char * const push_usage[] = {
|
||||
"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
|
||||
"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "exec_cmd.h"
|
||||
#include "commit.h"
|
||||
#include "object.h"
|
||||
#include "remote.h"
|
||||
#include "transport.h"
|
||||
|
||||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||
|
||||
@@ -462,14 +464,48 @@ static int delete_only(struct command *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
|
||||
{
|
||||
char *other = xstrdup(make_absolute_path(e->base));
|
||||
size_t len = strlen(other);
|
||||
struct remote *remote;
|
||||
struct transport *transport;
|
||||
const struct ref *extra;
|
||||
|
||||
while (other[len-1] == '/')
|
||||
other[--len] = '\0';
|
||||
if (len < 8 || memcmp(other + len - 8, "/objects", 8))
|
||||
return 0;
|
||||
/* Is this a git repository with refs? */
|
||||
memcpy(other + len - 8, "/refs", 6);
|
||||
if (!is_directory(other))
|
||||
return 0;
|
||||
other[len - 8] = '\0';
|
||||
remote = remote_get(other);
|
||||
transport = transport_get(remote, other);
|
||||
for (extra = transport_get_remote_refs(transport);
|
||||
extra;
|
||||
extra = extra->next) {
|
||||
add_extra_ref(".have", extra->old_sha1, 0);
|
||||
}
|
||||
transport_disconnect(transport);
|
||||
free(other);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_alternate_refs(void)
|
||||
{
|
||||
foreach_alt_odb(add_refs_from_alternate, NULL);
|
||||
}
|
||||
|
||||
int cmd_receive_pack(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
char *dir = NULL;
|
||||
|
||||
argv++;
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *arg = *argv++;
|
||||
const char *arg = *argv++;
|
||||
|
||||
if (*arg == '-') {
|
||||
/* Do flag handling here */
|
||||
@@ -477,7 +513,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
if (dir)
|
||||
usage(receive_pack_usage);
|
||||
dir = arg;
|
||||
dir = xstrdup(arg);
|
||||
}
|
||||
if (!dir)
|
||||
usage(receive_pack_usage);
|
||||
@@ -497,7 +533,9 @@ int main(int argc, char **argv)
|
||||
else if (0 <= receive_unpack_limit)
|
||||
unpack_limit = receive_unpack_limit;
|
||||
|
||||
add_alternate_refs();
|
||||
write_head_info();
|
||||
clear_extra_refs();
|
||||
|
||||
/* EOF */
|
||||
packet_flush(1);
|
||||
@@ -650,10 +650,13 @@ static int get_one_entry(struct remote *remote, void *priv)
|
||||
{
|
||||
struct string_list *list = priv;
|
||||
|
||||
string_list_append(remote->name, list)->util = remote->url_nr ?
|
||||
(void *)remote->url[0] : NULL;
|
||||
if (remote->url_nr > 1)
|
||||
warning("Remote %s has more than one URL", remote->name);
|
||||
if (remote->url_nr > 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < remote->url_nr; i++)
|
||||
string_list_append(remote->name, list)->util = (void *)remote->url[i];
|
||||
} else
|
||||
string_list_append(remote->name, list)->util = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -669,10 +672,14 @@ static int show_all(void)
|
||||
sort_string_list(&list);
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
struct string_list_item *item = list.items + i;
|
||||
printf("%s%s%s\n", item->string,
|
||||
verbose ? "\t" : "",
|
||||
verbose && item->util ?
|
||||
(const char *)item->util : "");
|
||||
if (verbose)
|
||||
printf("%s\t%s\n", item->string,
|
||||
item->util ? (const char *)item->util : "");
|
||||
else {
|
||||
if (i && !strcmp((item - 1)->string, item->string))
|
||||
continue;
|
||||
printf("%s\n", item->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -121,6 +121,9 @@ static void update_index_from_diff(struct diff_queue_struct *q,
|
||||
struct cache_entry *ce;
|
||||
ce = make_cache_entry(one->mode, one->sha1, one->path,
|
||||
0, 0);
|
||||
if (!ce)
|
||||
die("make_cache_entry failed for path '%s'",
|
||||
one->path);
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
|
||||
ADD_CACHE_OK_TO_REPLACE);
|
||||
} else
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "rerere.h"
|
||||
#include "merge-recursive.h"
|
||||
|
||||
/*
|
||||
* This implements the builtins revert and cherry-pick.
|
||||
@@ -201,36 +202,6 @@ static void set_author_ident_env(const char *message)
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
}
|
||||
|
||||
static int merge_recursive(const char *base_sha1,
|
||||
const char *head_sha1, const char *head_name,
|
||||
const char *next_sha1, const char *next_name)
|
||||
{
|
||||
char buffer[256];
|
||||
const char *argv[6];
|
||||
int i = 0;
|
||||
|
||||
sprintf(buffer, "GITHEAD_%s", head_sha1);
|
||||
setenv(buffer, head_name, 1);
|
||||
sprintf(buffer, "GITHEAD_%s", next_sha1);
|
||||
setenv(buffer, next_name, 1);
|
||||
|
||||
/*
|
||||
* This three way merge is an interesting one. We are at
|
||||
* $head, and would want to apply the change between $commit
|
||||
* and $prev on top of us (when reverting), or the change between
|
||||
* $prev and $commit on top of us (when cherry-picking or replaying).
|
||||
*/
|
||||
argv[i++] = "merge-recursive";
|
||||
if (base_sha1)
|
||||
argv[i++] = base_sha1;
|
||||
argv[i++] = "--";
|
||||
argv[i++] = head_sha1;
|
||||
argv[i++] = next_sha1;
|
||||
argv[i++] = NULL;
|
||||
|
||||
return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
|
||||
}
|
||||
|
||||
static char *help_msg(const unsigned char *sha1)
|
||||
{
|
||||
static char helpbuf[1024];
|
||||
@@ -263,14 +234,27 @@ static int index_is_dirty(void)
|
||||
return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
|
||||
}
|
||||
|
||||
static struct tree *empty_tree(void)
|
||||
{
|
||||
struct tree *tree = xcalloc(1, sizeof(struct tree));
|
||||
|
||||
tree->object.parsed = 1;
|
||||
tree->object.type = OBJ_TREE;
|
||||
pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
|
||||
return tree;
|
||||
}
|
||||
|
||||
static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
{
|
||||
unsigned char head[20];
|
||||
struct commit *base, *next, *parent;
|
||||
int i;
|
||||
int i, index_fd, clean;
|
||||
char *oneline, *reencoded_message = NULL;
|
||||
const char *message, *encoding;
|
||||
const char *defmsg = xstrdup(git_path("MERGE_MSG"));
|
||||
struct merge_options o;
|
||||
struct tree *result, *next_tree, *base_tree, *head_tree;
|
||||
static struct lock_file index_lock;
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
me = action == REVERT ? "revert" : "cherry-pick";
|
||||
@@ -281,6 +265,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
if (action == REVERT && !no_replay)
|
||||
die("revert is incompatible with replay");
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("git %s: failed to read the index", me);
|
||||
if (no_commit) {
|
||||
/*
|
||||
* We do not intend to commit immediately. We just want to
|
||||
@@ -293,12 +279,12 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
} else {
|
||||
if (get_sha1("HEAD", head))
|
||||
die ("You do not have a valid HEAD");
|
||||
if (read_cache() < 0)
|
||||
die("could not read the index");
|
||||
if (index_is_dirty())
|
||||
die ("Dirty index: cannot %s", me);
|
||||
discard_cache();
|
||||
}
|
||||
discard_cache();
|
||||
|
||||
index_fd = hold_locked_index(&index_lock, 1);
|
||||
|
||||
if (!commit->parents) {
|
||||
if (action == REVERT)
|
||||
@@ -332,6 +318,10 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
die ("Cannot get commit message for %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (parent && parse_commit(parent) < 0)
|
||||
die("%s: cannot parse parent commit %s",
|
||||
me, sha1_to_hex(parent->object.sha1));
|
||||
|
||||
/*
|
||||
* "commit" is an existing commit. We would want to apply
|
||||
* the difference it introduces since its first parent "prev"
|
||||
@@ -374,13 +364,26 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (merge_recursive(base == NULL ?
|
||||
NULL : sha1_to_hex(base->object.sha1),
|
||||
sha1_to_hex(head), "HEAD",
|
||||
sha1_to_hex(next->object.sha1), oneline) ||
|
||||
write_cache_as_tree(head, 0, NULL)) {
|
||||
read_cache();
|
||||
init_merge_options(&o);
|
||||
o.branch1 = "HEAD";
|
||||
o.branch2 = oneline;
|
||||
|
||||
head_tree = parse_tree_indirect(head);
|
||||
next_tree = next ? next->tree : empty_tree();
|
||||
base_tree = base ? base->tree : empty_tree();
|
||||
|
||||
clean = merge_trees(&o,
|
||||
head_tree,
|
||||
next_tree, base_tree, &result);
|
||||
|
||||
if (active_cache_changed &&
|
||||
(write_cache(index_fd, active_cache, active_nr) ||
|
||||
commit_locked_index(&index_lock)))
|
||||
die("%s: Unable to write new index file", me);
|
||||
|
||||
if (!clean) {
|
||||
add_to_msg("\nConflicts:\n\n");
|
||||
read_cache();
|
||||
for (i = 0; i < active_nr;) {
|
||||
struct cache_entry *ce = active_cache[i++];
|
||||
if (ce_stage(ce)) {
|
||||
|
||||
23
builtin-rm.c
23
builtin-rm.c
@@ -29,26 +29,6 @@ static void add_list(const char *name)
|
||||
list.name[list.nr++] = name;
|
||||
}
|
||||
|
||||
static int remove_file(const char *name)
|
||||
{
|
||||
int ret;
|
||||
char *slash;
|
||||
|
||||
ret = unlink(name);
|
||||
if (ret && errno == ENOENT)
|
||||
/* The user has removed it from the filesystem by hand */
|
||||
ret = errno = 0;
|
||||
|
||||
if (!ret && (slash = strrchr(name, '/'))) {
|
||||
char *n = xstrdup(name);
|
||||
do {
|
||||
n[slash - name] = 0;
|
||||
name = n;
|
||||
} while (!rmdir(name) && (slash = strrchr(name, '/')));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_local_mod(unsigned char *head, int index_only)
|
||||
{
|
||||
/* items in list are already sorted in the cache order,
|
||||
@@ -157,6 +137,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
seen = NULL;
|
||||
@@ -239,7 +220,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
int removed = 0;
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
const char *path = list.name[i];
|
||||
if (!remove_file(path)) {
|
||||
if (!remove_path(path)) {
|
||||
removed = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ static struct send_pack_args args = {
|
||||
/*
|
||||
* Make a pack stream and spit it out into file descriptor fd
|
||||
*/
|
||||
static int pack_objects(int fd, struct ref *refs)
|
||||
static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
|
||||
{
|
||||
/*
|
||||
* The child becomes pack-objects --revs; we feed
|
||||
@@ -34,6 +34,8 @@ static int pack_objects(int fd, struct ref *refs)
|
||||
NULL,
|
||||
};
|
||||
struct child_process po;
|
||||
int i;
|
||||
char buf[42];
|
||||
|
||||
if (args.use_thin_pack)
|
||||
argv[4] = "--thin";
|
||||
@@ -49,9 +51,15 @@ static int pack_objects(int fd, struct ref *refs)
|
||||
* We feed the pack-objects we just spawned with revision
|
||||
* parameters by writing to the pipe.
|
||||
*/
|
||||
while (refs) {
|
||||
char buf[42];
|
||||
for (i = 0; i < extra->nr; i++) {
|
||||
memcpy(buf + 1, sha1_to_hex(&extra->array[i][0]), 40);
|
||||
buf[0] = '^';
|
||||
buf[41] = '\n';
|
||||
if (!write_or_whine(po.in, buf, 42, "send-pack: send refs"))
|
||||
break;
|
||||
}
|
||||
|
||||
while (refs) {
|
||||
if (!is_null_sha1(refs->old_sha1) &&
|
||||
has_sha1_file(refs->old_sha1)) {
|
||||
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
|
||||
@@ -381,14 +389,17 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
||||
int expect_status_report = 0;
|
||||
int flags = MATCH_REFS_NONE;
|
||||
int ret;
|
||||
struct extra_have_objects extra_have;
|
||||
|
||||
memset(&extra_have, 0, sizeof(extra_have));
|
||||
if (args.send_all)
|
||||
flags |= MATCH_REFS_ALL;
|
||||
if (args.send_mirror)
|
||||
flags |= MATCH_REFS_MIRROR;
|
||||
|
||||
/* No funny business with the matcher */
|
||||
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
|
||||
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
|
||||
&extra_have);
|
||||
get_local_heads();
|
||||
|
||||
/* Does the other end support the reporting? */
|
||||
@@ -496,7 +507,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
||||
|
||||
packet_flush(out);
|
||||
if (new_refs && !args.dry_run) {
|
||||
if (pack_objects(out, remote_refs) < 0)
|
||||
if (pack_objects(out, remote_refs, &extra_have) < 0)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -19,7 +19,7 @@ static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict]
|
||||
static unsigned char buffer[4096];
|
||||
static unsigned int offset, len;
|
||||
static off_t consumed_bytes;
|
||||
static SHA_CTX ctx;
|
||||
static git_SHA_CTX ctx;
|
||||
|
||||
/*
|
||||
* When running under --strict mode, objects whose reachability are
|
||||
@@ -59,7 +59,7 @@ static void *fill(int min)
|
||||
if (min > sizeof(buffer))
|
||||
die("cannot fill %d bytes", min);
|
||||
if (offset) {
|
||||
SHA1_Update(&ctx, buffer, offset);
|
||||
git_SHA1_Update(&ctx, buffer, offset);
|
||||
memmove(buffer, buffer + offset, len);
|
||||
offset = 0;
|
||||
}
|
||||
@@ -477,8 +477,7 @@ static void unpack_all(void)
|
||||
|
||||
if (!quiet)
|
||||
progress = start_progress("Unpacking objects", nr_objects);
|
||||
obj_list = xmalloc(nr_objects * sizeof(*obj_list));
|
||||
memset(obj_list, 0, nr_objects * sizeof(*obj_list));
|
||||
obj_list = xcalloc(nr_objects, sizeof(*obj_list));
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
unpack_one(i);
|
||||
display_progress(progress, i + 1);
|
||||
@@ -539,10 +538,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
||||
/* We don't take any non-flag arguments now.. Maybe some day */
|
||||
usage(unpack_usage);
|
||||
}
|
||||
SHA1_Init(&ctx);
|
||||
git_SHA1_Init(&ctx);
|
||||
unpack_all();
|
||||
SHA1_Update(&ctx, buffer, offset);
|
||||
SHA1_Final(sha1, &ctx);
|
||||
git_SHA1_Update(&ctx, buffer, offset);
|
||||
git_SHA1_Final(sha1, &ctx);
|
||||
if (strict)
|
||||
write_rest();
|
||||
if (hashcmp(fill(20), sha1))
|
||||
|
||||
@@ -17,7 +17,8 @@ extern int read_line_with_nul(char *buf, int size, FILE *file);
|
||||
extern int fmt_merge_msg(int merge_summary, struct strbuf *in,
|
||||
struct strbuf *out);
|
||||
extern int commit_tree(const char *msg, unsigned char *tree,
|
||||
struct commit_list *parents, unsigned char *ret);
|
||||
struct commit_list *parents, unsigned char *ret,
|
||||
const char *author);
|
||||
extern int check_pager_config(const char *cmd);
|
||||
|
||||
extern int cmd_add(int argc, const char **argv, const char *prefix);
|
||||
@@ -78,6 +79,7 @@ extern int cmd_prune(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_push(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_remote(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_config(int argc, const char **argv, const char *prefix);
|
||||
|
||||
21
cache.h
21
cache.h
@@ -6,8 +6,14 @@
|
||||
#include "hash.h"
|
||||
|
||||
#include SHA1_HEADER
|
||||
#include <zlib.h>
|
||||
#ifndef git_SHA_CTX
|
||||
#define git_SHA_CTX SHA_CTX
|
||||
#define git_SHA1_Init SHA1_Init
|
||||
#define git_SHA1_Update SHA1_Update
|
||||
#define git_SHA1_Final SHA1_Final
|
||||
#endif
|
||||
|
||||
#include <zlib.h>
|
||||
#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
|
||||
#define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
|
||||
#endif
|
||||
@@ -313,6 +319,7 @@ extern int is_bare_repository(void);
|
||||
extern int is_inside_git_dir(void);
|
||||
extern char *git_work_tree_cfg;
|
||||
extern int is_inside_work_tree(void);
|
||||
extern int have_git_dir(void);
|
||||
extern const char *get_git_dir(void);
|
||||
extern char *get_object_directory(void);
|
||||
extern char *get_index_file(void);
|
||||
@@ -371,6 +378,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name
|
||||
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
|
||||
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
|
||||
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
|
||||
#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
|
||||
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
|
||||
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
|
||||
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
|
||||
@@ -380,6 +388,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);
|
||||
#define ADD_CACHE_PRETEND 2
|
||||
#define ADD_CACHE_IGNORE_ERRORS 4
|
||||
#define ADD_CACHE_IGNORE_REMOVAL 8
|
||||
#define ADD_CACHE_INTENT 16
|
||||
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
|
||||
extern int add_file_to_index(struct index_state *, const char *path, int flags);
|
||||
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
|
||||
@@ -533,6 +542,7 @@ static inline int is_absolute_path(const char *path)
|
||||
{
|
||||
return path[0] == '/' || has_dos_drive_prefix(path);
|
||||
}
|
||||
int is_directory(const char *);
|
||||
const char *make_absolute_path(const char *path);
|
||||
const char *make_nonrelative_path(const char *path);
|
||||
const char *make_relative_path(const char *abs, const char *base);
|
||||
@@ -640,6 +650,8 @@ extern struct alternate_object_database {
|
||||
} *alt_odb_list;
|
||||
extern void prepare_alt_odb(void);
|
||||
extern void add_to_alternates_file(const char *reference);
|
||||
typedef int alt_odb_fn(struct alternate_object_database *, void *);
|
||||
extern void foreach_alt_odb(alt_odb_fn, void*);
|
||||
|
||||
struct pack_window {
|
||||
struct pack_window *next;
|
||||
@@ -708,7 +720,11 @@ extern struct child_process *git_connect(int fd[2], const char *url, const char
|
||||
extern int finish_connect(struct child_process *conn);
|
||||
extern int path_match(const char *path, int nr, char **match);
|
||||
extern int get_ack(int fd, unsigned char *result_sha1);
|
||||
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
|
||||
struct extra_have_objects {
|
||||
int nr, alloc;
|
||||
unsigned char (*array)[20];
|
||||
};
|
||||
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
|
||||
extern int server_supports(const char *feature);
|
||||
|
||||
extern struct packed_git *parse_pack_index(unsigned char *sha1);
|
||||
@@ -742,7 +758,6 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
|
||||
extern int git_default_config(const char *, const char *, void *);
|
||||
extern int git_config_from_file(config_fn_t fn, const char *, void *);
|
||||
extern int git_config(config_fn_t fn, void *);
|
||||
extern int git_parse_long(const char *, long *);
|
||||
extern int git_parse_ulong(const char *, unsigned long *);
|
||||
extern int git_config_int(const char *, const char *);
|
||||
extern unsigned long git_config_ulong(const char *, const char *);
|
||||
|
||||
2
commit.c
2
commit.c
@@ -160,7 +160,7 @@ struct commit_graft *read_graft_line(char *buf, int len)
|
||||
return graft;
|
||||
}
|
||||
|
||||
int read_graft_file(const char *graft_file)
|
||||
static int read_graft_file(const char *graft_file)
|
||||
{
|
||||
FILE *fp = fopen(graft_file, "r");
|
||||
char buf[1024];
|
||||
|
||||
1
commit.h
1
commit.h
@@ -118,7 +118,6 @@ struct commit_graft {
|
||||
|
||||
struct commit_graft *read_graft_line(char *buf, int len);
|
||||
int register_commit_graft(struct commit_graft *, int);
|
||||
int read_graft_file(const char *graft_file);
|
||||
struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
|
||||
|
||||
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
|
||||
|
||||
127
compat/cygwin.c
Normal file
127
compat/cygwin.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "../git-compat-util.h"
|
||||
#include "win32.h"
|
||||
#include "../cache.h" /* to read configuration */
|
||||
|
||||
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
|
||||
{
|
||||
long long winTime = ((long long)ft->dwHighDateTime << 32) +
|
||||
ft->dwLowDateTime;
|
||||
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
|
||||
/* convert 100-nsecond interval to seconds and nanoseconds */
|
||||
ts->tv_sec = (time_t)(winTime/10000000);
|
||||
ts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;
|
||||
}
|
||||
|
||||
#define size_to_blocks(s) (((s)+511)/512)
|
||||
|
||||
/* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
|
||||
*
|
||||
* To simplify its logic, in the case of cygwin symlinks, this implementation
|
||||
* falls back to the cygwin version of stat/lstat, which is provided as the
|
||||
* last argument.
|
||||
*/
|
||||
static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA fdata;
|
||||
|
||||
if (file_name[0] == '/')
|
||||
return cygstat (file_name, buf);
|
||||
|
||||
if (!(errno = get_file_attr(file_name, &fdata))) {
|
||||
/*
|
||||
* If the system attribute is set and it is not a directory then
|
||||
* it could be a symbol link created in the nowinsymlinks mode.
|
||||
* Normally, Cygwin works in the winsymlinks mode, so this situation
|
||||
* is very unlikely. For the sake of simplicity of our code, let's
|
||||
* Cygwin to handle it.
|
||||
*/
|
||||
if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
|
||||
!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
return cygstat(file_name, buf);
|
||||
|
||||
/* fill out the stat structure */
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_ino = 0;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_nlink = 1;
|
||||
buf->st_uid = buf->st_gid = 0;
|
||||
#ifdef __CYGWIN_USE_BIG_TYPES__
|
||||
buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +
|
||||
fdata.nFileSizeLow;
|
||||
#else
|
||||
buf->st_size = (off_t)fdata.nFileSizeLow;
|
||||
#endif
|
||||
buf->st_blocks = size_to_blocks(buf->st_size);
|
||||
filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);
|
||||
filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);
|
||||
filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);
|
||||
return 0;
|
||||
} else if (errno == ENOENT) {
|
||||
/*
|
||||
* In the winsymlinks mode (which is the default), Cygwin
|
||||
* emulates symbol links using Windows shortcut files. These
|
||||
* files are formed by adding .lnk extension. So, if we have
|
||||
* not found the specified file name, it could be that it is
|
||||
* a symbol link. Let's Cygwin to deal with that.
|
||||
*/
|
||||
return cygstat(file_name, buf);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We provide our own lstat/stat functions, since the provided Cygwin versions
|
||||
* of these functions are too slow. These stat functions are tailored for Git's
|
||||
* usage, and therefore they are not meant to be complete and correct emulation
|
||||
* of lstat/stat functionality.
|
||||
*/
|
||||
static int cygwin_lstat(const char *path, struct stat *buf)
|
||||
{
|
||||
return do_stat(path, buf, lstat);
|
||||
}
|
||||
|
||||
static int cygwin_stat(const char *path, struct stat *buf)
|
||||
{
|
||||
return do_stat(path, buf, stat);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* At start up, we are trying to determine whether Win32 API or cygwin stat
|
||||
* functions should be used. The choice is determined by core.ignorecygwinfstricks.
|
||||
* Reading this option is not always possible immediately as git_dir may be
|
||||
* not be set yet. So until it is set, use cygwin lstat/stat functions.
|
||||
*/
|
||||
static int native_stat = 1;
|
||||
|
||||
static int git_cygwin_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "core.ignorecygwinfstricks"))
|
||||
native_stat = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_stat(void)
|
||||
{
|
||||
if (have_git_dir()) {
|
||||
git_config(git_cygwin_config, NULL);
|
||||
cygwin_stat_fn = native_stat ? cygwin_stat : stat;
|
||||
cygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cygwin_stat_stub(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return (init_stat() ? stat : *cygwin_stat_fn)(file_name, buf);
|
||||
}
|
||||
|
||||
static int cygwin_lstat_stub(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
|
||||
}
|
||||
|
||||
stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
|
||||
stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
|
||||
|
||||
9
compat/cygwin.h
Normal file
9
compat/cygwin.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef int (*stat_fn_t)(const char*, struct stat*);
|
||||
extern stat_fn_t cygwin_stat_fn;
|
||||
extern stat_fn_t cygwin_lstat_fn;
|
||||
|
||||
#define stat(path, buf) (*cygwin_stat_fn)(path, buf)
|
||||
#define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../git-compat-util.h"
|
||||
#include "win32.h"
|
||||
#include "../strbuf.h"
|
||||
|
||||
unsigned int _CRT_fmode = _O_BINARY;
|
||||
@@ -31,7 +32,6 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
|
||||
return (time_t)winTime;
|
||||
}
|
||||
|
||||
extern int _getdrive( void );
|
||||
/* We keep the do_lstat code in a separate function to avoid recursion.
|
||||
* When a path ends with a slash, the stat will fail with ENOENT. In
|
||||
* this case, we strip the trailing slashes and stat again.
|
||||
@@ -40,46 +40,19 @@ static int do_lstat(const char *file_name, struct stat *buf)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA fdata;
|
||||
|
||||
if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
|
||||
int fMode = S_IREAD;
|
||||
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
|
||||
if (!(errno = get_file_attr(file_name, &fdata))) {
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = fMode;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
|
||||
buf->st_dev = buf->st_rdev = (_getdrive() - 1);
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
|
||||
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
case ERROR_SHARING_BUFFER_EXCEEDED:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -131,21 +104,13 @@ int mingw_fstat(int fd, struct stat *buf)
|
||||
return fstat(fd, buf);
|
||||
|
||||
if (GetFileInformationByHandle(fh, &fdata)) {
|
||||
int fMode = S_IREAD;
|
||||
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = fMode;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
|
||||
buf->st_dev = buf->st_rdev = (_getdrive() - 1);
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
|
||||
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
|
||||
|
||||
34
compat/win32.h
Normal file
34
compat/win32.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* common Win32 functions for MinGW and Cygwin */
|
||||
#include <windows.h>
|
||||
|
||||
static inline int file_attr_to_st_mode (DWORD attr)
|
||||
{
|
||||
int fMode = S_IREAD;
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(attr & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
return fMode;
|
||||
}
|
||||
|
||||
static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
|
||||
{
|
||||
if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
|
||||
return 0;
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
case ERROR_SHARING_BUFFER_EXCEEDED:
|
||||
return EACCES;
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
return ENAMETOOLONG;
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return ENOMEM;
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
||||
23
config.c
23
config.c
@@ -205,8 +205,27 @@ static int git_parse_file(config_fn_t fn, void *data)
|
||||
int baselen = 0;
|
||||
static char var[MAXNAME];
|
||||
|
||||
/* U+FEFF Byte Order Mark in UTF8 */
|
||||
static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
|
||||
const unsigned char *bomptr = utf8_bom;
|
||||
|
||||
for (;;) {
|
||||
int c = get_next_char();
|
||||
if (bomptr && *bomptr) {
|
||||
/* We are at the file beginning; skip UTF8-encoded BOM
|
||||
* if present. Sane editors won't put this in on their
|
||||
* own, but e.g. Windows Notepad will do it happily. */
|
||||
if ((unsigned char) c == *bomptr) {
|
||||
bomptr++;
|
||||
continue;
|
||||
} else {
|
||||
/* Do not tolerate partial BOM. */
|
||||
if (bomptr != utf8_bom)
|
||||
break;
|
||||
/* No BOM at file beginning. Cool. */
|
||||
bomptr = NULL;
|
||||
}
|
||||
}
|
||||
if (c == '\n') {
|
||||
if (config_file_eof)
|
||||
return 0;
|
||||
@@ -255,7 +274,7 @@ static int parse_unit_factor(const char *end, unsigned long *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_parse_long(const char *value, long *ret)
|
||||
static int git_parse_long(const char *value, long *ret)
|
||||
{
|
||||
if (value && *value) {
|
||||
char *end;
|
||||
@@ -291,7 +310,7 @@ static void die_bad_config(const char *name)
|
||||
|
||||
int git_config_int(const char *name, const char *value)
|
||||
{
|
||||
long ret;
|
||||
long ret = 0;
|
||||
if (!git_parse_long(value, &ret))
|
||||
die_bad_config(name);
|
||||
return ret;
|
||||
|
||||
16
connect.c
16
connect.c
@@ -41,12 +41,20 @@ int check_ref_type(const struct ref *ref, int flags)
|
||||
return check_ref(ref->name, strlen(ref->name), flags);
|
||||
}
|
||||
|
||||
static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
|
||||
{
|
||||
ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
|
||||
hashcpy(&(extra->array[extra->nr][0]), sha1);
|
||||
extra->nr++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read all the refs from the other end
|
||||
*/
|
||||
struct ref **get_remote_heads(int in, struct ref **list,
|
||||
int nr_match, char **match,
|
||||
unsigned int flags)
|
||||
unsigned int flags,
|
||||
struct extra_have_objects *extra_have)
|
||||
{
|
||||
*list = NULL;
|
||||
for (;;) {
|
||||
@@ -72,6 +80,12 @@ struct ref **get_remote_heads(int in, struct ref **list,
|
||||
server_capabilities = xstrdup(name + name_len + 1);
|
||||
}
|
||||
|
||||
if (extra_have &&
|
||||
name_len == 5 && !memcmp(".have", name, 5)) {
|
||||
add_extra_have(extra_have, old_sha1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!check_ref(name, name_len, flags))
|
||||
continue;
|
||||
if (nr_match && !path_match(name, nr_match, match))
|
||||
|
||||
@@ -785,14 +785,9 @@ _git_fetch ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-fetch*,1)
|
||||
if [ "$COMP_CWORD" = 2 ]; then
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
git,2)
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
else
|
||||
case "$cur" in
|
||||
*:*)
|
||||
local pfx=""
|
||||
@@ -811,8 +806,7 @@ _git_fetch ()
|
||||
__gitcomp "$(__git_refs2 "$remote")"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
_git_format_patch ()
|
||||
@@ -1049,36 +1043,25 @@ _git_pull ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-pull*,1)
|
||||
if [ "$COMP_CWORD" = 2 ]; then
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
git,2)
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
else
|
||||
local remote
|
||||
case "${COMP_WORDS[0]}" in
|
||||
git-pull) remote="${COMP_WORDS[1]}" ;;
|
||||
git) remote="${COMP_WORDS[2]}" ;;
|
||||
esac
|
||||
__gitcomp "$(__git_refs "$remote")"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
_git_push ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-push*,1)
|
||||
if [ "$COMP_CWORD" = 2 ]; then
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
git,2)
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
else
|
||||
case "$cur" in
|
||||
*:*)
|
||||
local remote
|
||||
@@ -1102,8 +1085,7 @@ _git_push ()
|
||||
__gitcomp "$(__git_refs)"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
_git_rebase ()
|
||||
@@ -1141,7 +1123,8 @@ _git_send_email ()
|
||||
--no-suppress-from --no-thread --quiet
|
||||
--signed-off-by-cc --smtp-pass --smtp-server
|
||||
--smtp-server-port --smtp-ssl --smtp-user --subject
|
||||
--suppress-cc --suppress-from --thread --to"
|
||||
--suppress-cc --suppress-from --thread --to
|
||||
--validate --no-validate"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify if you are on battery, in case you
|
||||
# are running Linux. Called by git-gc --auto with no arguments. The hook
|
||||
# should exit with non-zero status after issuing an appropriate message
|
||||
# if it wants to stop the auto repacking.
|
||||
# are running Linux or OS X. Called by git-gc --auto with no arguments.
|
||||
# The hook should exit with non-zero status after issuing an appropriate
|
||||
# message if it wants to stop the auto repacking.
|
||||
#
|
||||
# This hook is stored in the contrib/hooks directory. Your distribution
|
||||
# may have put this somewhere else. If you want to use this hook, you
|
||||
@@ -28,6 +28,10 @@ elif grep -q 'on-line' /proc/acpi/ac_adapter/AC/state 2>/dev/null
|
||||
then
|
||||
exit 0
|
||||
elif grep -q '0x01$' /proc/apm 2>/dev/null
|
||||
then
|
||||
exit 0
|
||||
elif test -x /usr/bin/pmset && /usr/bin/pmset -g batt |
|
||||
grep -q "Currently drawing from 'AC Power'"
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
52
contrib/rerere-train.sh
Executable file
52
contrib/rerere-train.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2008, Nanako Shiraishi
|
||||
# Prime rerere database from existing merge commits
|
||||
|
||||
me=rerere-train
|
||||
USAGE="$me rev-list-args"
|
||||
|
||||
SUBDIRECTORY_OK=Yes
|
||||
OPTIONS_SPEC=
|
||||
. git-sh-setup
|
||||
require_work_tree
|
||||
cd_to_toplevel
|
||||
|
||||
# Remember original branch
|
||||
branch=$(git symbolic-ref -q HEAD) ||
|
||||
original_HEAD=$(git rev-parse --verify HEAD) || {
|
||||
echo >&2 "Not on any branch and no commit yet?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$GIT_DIR/rr-cache" || exit
|
||||
|
||||
git rev-list --parents "$@" |
|
||||
while read commit parent1 other_parents
|
||||
do
|
||||
if test -z "$other_parents"
|
||||
then
|
||||
# Skip non-merges
|
||||
continue
|
||||
fi
|
||||
git checkout -q "$parent1^0"
|
||||
if git merge $other_parents >/dev/null 2>&1
|
||||
then
|
||||
# Cleanly merges
|
||||
continue
|
||||
fi
|
||||
if test -s "$GIT_DIR/MERGE_RR"
|
||||
then
|
||||
git show -s --pretty=format:"Learning from %h %s" "$commit"
|
||||
git rerere
|
||||
git checkout -q $commit -- .
|
||||
git rerere
|
||||
fi
|
||||
git reset -q --hard
|
||||
done
|
||||
|
||||
if test -z "$branch"
|
||||
then
|
||||
git checkout "$original_HEAD"
|
||||
else
|
||||
git checkout "${branch#refs/heads/}"
|
||||
fi
|
||||
@@ -1,8 +1,30 @@
|
||||
To syntax highlight git's commit messages, you need to:
|
||||
1. Copy syntax/gitcommit.vim to vim's syntax directory:
|
||||
$ mkdir -p $HOME/.vim/syntax
|
||||
$ cp syntax/gitcommit.vim $HOME/.vim/syntax
|
||||
2. Auto-detect the editing of git commit files:
|
||||
$ cat >>$HOME/.vimrc <<'EOF'
|
||||
autocmd BufNewFile,BufRead COMMIT_EDITMSG set filetype=gitcommit
|
||||
EOF
|
||||
Syntax highlighting for git commit messages, config files, etc. is
|
||||
included with the vim distribution as of vim 7.2, and should work
|
||||
automatically.
|
||||
|
||||
If you have an older version of vim, you can get the latest syntax
|
||||
files from the vim project:
|
||||
|
||||
http://vim.svn.sourceforge.net/viewvc/vim/trunk/runtime/syntax/git.vim
|
||||
http://vim.svn.sourceforge.net/viewvc/vim/trunk/runtime/syntax/gitcommit.vim
|
||||
http://vim.svn.sourceforge.net/viewvc/vim/trunk/runtime/syntax/gitconfig.vim
|
||||
http://vim.svn.sourceforge.net/viewvc/vim/trunk/runtime/syntax/gitrebase.vim
|
||||
http://vim.svn.sourceforge.net/viewvc/vim/trunk/runtime/syntax/gitsendemail.vim
|
||||
|
||||
To install:
|
||||
|
||||
1. Copy these files to vim's syntax directory $HOME/.vim/syntax
|
||||
2. To auto-detect the editing of various git-related filetypes:
|
||||
$ cat >>$HOME/.vim/filetype.vim <<'EOF'
|
||||
autocmd BufNewFile,BufRead *.git/COMMIT_EDITMSG setf gitcommit
|
||||
autocmd BufNewFile,BufRead *.git/config,.gitconfig setf gitconfig
|
||||
autocmd BufNewFile,BufRead git-rebase-todo setf gitrebase
|
||||
autocmd BufNewFile,BufRead .msg.[0-9]*
|
||||
\ if getline(1) =~ '^From.*# This line is ignored.$' |
|
||||
\ setf gitsendemail |
|
||||
\ endif
|
||||
autocmd BufNewFile,BufRead *.git/**
|
||||
\ if getline(1) =~ '^\x\{40\}\>\|^ref: ' |
|
||||
\ setf git |
|
||||
\ endif
|
||||
EOF
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
syn region gitLine start=/^#/ end=/$/
|
||||
syn region gitCommit start=/^# Changes to be committed:$/ end=/^#$/ contains=gitHead,gitCommitFile
|
||||
syn region gitHead contained start=/^# (.*)/ end=/^#$/
|
||||
syn region gitChanged start=/^# Changed but not updated:/ end=/^#$/ contains=gitHead,gitChangedFile
|
||||
syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
|
||||
|
||||
syn match gitCommitFile contained /^#\t.*/hs=s+2
|
||||
syn match gitChangedFile contained /^#\t.*/hs=s+2
|
||||
syn match gitUntrackedFile contained /^#\t.*/hs=s+2
|
||||
|
||||
hi def link gitLine Comment
|
||||
hi def link gitCommit Comment
|
||||
hi def link gitChanged Comment
|
||||
hi def link gitHead Comment
|
||||
hi def link gitUntracked Comment
|
||||
hi def link gitCommitFile Type
|
||||
hi def link gitChangedFile Constant
|
||||
hi def link gitUntrackedFile Constant
|
||||
@@ -36,11 +36,11 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
|
||||
unsigned offset = f->offset;
|
||||
|
||||
if (offset) {
|
||||
SHA1_Update(&f->ctx, f->buffer, offset);
|
||||
git_SHA1_Update(&f->ctx, f->buffer, offset);
|
||||
sha1flush(f, f->buffer, offset);
|
||||
f->offset = 0;
|
||||
}
|
||||
SHA1_Final(f->buffer, &f->ctx);
|
||||
git_SHA1_Final(f->buffer, &f->ctx);
|
||||
if (result)
|
||||
hashcpy(result, f->buffer);
|
||||
if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
|
||||
@@ -82,7 +82,7 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
|
||||
buf = (char *) buf + nr;
|
||||
left -= nr;
|
||||
if (!left) {
|
||||
SHA1_Update(&f->ctx, data, offset);
|
||||
git_SHA1_Update(&f->ctx, data, offset);
|
||||
sha1flush(f, data, offset);
|
||||
offset = 0;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp
|
||||
f->tp = tp;
|
||||
f->name = name;
|
||||
f->do_crc = 0;
|
||||
SHA1_Init(&f->ctx);
|
||||
git_SHA1_Init(&f->ctx);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ struct progress;
|
||||
struct sha1file {
|
||||
int fd;
|
||||
unsigned int offset;
|
||||
SHA_CTX ctx;
|
||||
git_SHA_CTX ctx;
|
||||
off_t total;
|
||||
struct progress *tp;
|
||||
const char *name;
|
||||
|
||||
10
daemon.c
10
daemon.c
@@ -1116,13 +1116,9 @@ int main(int argc, char **argv)
|
||||
if (strict_paths && (!ok_paths || !*ok_paths))
|
||||
die("option --strict-paths requires a whitelist");
|
||||
|
||||
if (base_path) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(base_path, &st) || !S_ISDIR(st.st_mode))
|
||||
die("base-path '%s' does not exist or "
|
||||
"is not a directory", base_path);
|
||||
}
|
||||
if (base_path && !is_directory(base_path))
|
||||
die("base-path '%s' does not exist or is not a directory",
|
||||
base_path);
|
||||
|
||||
if (inetd_mode) {
|
||||
struct sockaddr_storage ss;
|
||||
|
||||
26
date.c
26
date.c
@@ -402,6 +402,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
|
||||
return end - date;
|
||||
}
|
||||
|
||||
/* Have we filled in any part of the time/date yet? */
|
||||
static inline int nodate(struct tm *tm)
|
||||
{
|
||||
return tm->tm_year < 0 &&
|
||||
tm->tm_mon < 0 &&
|
||||
tm->tm_mday < 0 &&
|
||||
!(tm->tm_hour | tm->tm_min | tm->tm_sec);
|
||||
}
|
||||
|
||||
/*
|
||||
* We've seen a digit. Time? Year? Date?
|
||||
*/
|
||||
@@ -418,7 +427,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
|
||||
* more than 8 digits. This is because we don't want to rule out
|
||||
* numbers like 20070606 as a YYYYMMDD date.
|
||||
*/
|
||||
if (num >= 100000000) {
|
||||
if (num >= 100000000 && nodate(tm)) {
|
||||
time_t time = num;
|
||||
if (gmtime_r(&time, tm)) {
|
||||
*tm_gmt = 1;
|
||||
@@ -462,6 +471,13 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore lots of numerals. We took care of 4-digit years above.
|
||||
* Days or months must be one or two digits.
|
||||
*/
|
||||
if (n > 2)
|
||||
return n;
|
||||
|
||||
/*
|
||||
* NOTE! We will give precedence to day-of-month over month or
|
||||
* year numbers in the 1-12 range. So 05 is always "mday 5",
|
||||
@@ -488,10 +504,6 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
|
||||
|
||||
if (num > 0 && num < 32) {
|
||||
tm->tm_mday = num;
|
||||
} else if (num > 1900) {
|
||||
tm->tm_year = num - 1900;
|
||||
} else if (num > 70) {
|
||||
tm->tm_year = num;
|
||||
} else if (num > 0 && num < 13) {
|
||||
tm->tm_mon = num-1;
|
||||
}
|
||||
@@ -823,7 +835,9 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
|
||||
}
|
||||
}
|
||||
|
||||
*num = number;
|
||||
/* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */
|
||||
if (date[0] != '0' || end - date <= 2)
|
||||
*num = number;
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
140
diff.c
140
diff.c
@@ -96,32 +96,37 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
|
||||
* to define a customized regexp to find the beginning of a function to
|
||||
* be used for hunk header lines of "diff -p" style output.
|
||||
*/
|
||||
static struct funcname_pattern {
|
||||
struct funcname_pattern_entry {
|
||||
char *name;
|
||||
char *pattern;
|
||||
struct funcname_pattern *next;
|
||||
int cflags;
|
||||
};
|
||||
static struct funcname_pattern_list {
|
||||
struct funcname_pattern_list *next;
|
||||
struct funcname_pattern_entry e;
|
||||
} *funcname_pattern_list;
|
||||
|
||||
static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
|
||||
static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
|
||||
{
|
||||
const char *name;
|
||||
int namelen;
|
||||
struct funcname_pattern *pp;
|
||||
struct funcname_pattern_list *pp;
|
||||
|
||||
name = var + 5; /* "diff." */
|
||||
namelen = ep - name;
|
||||
|
||||
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
||||
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
|
||||
if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
|
||||
break;
|
||||
if (!pp) {
|
||||
pp = xcalloc(1, sizeof(*pp));
|
||||
pp->name = xmemdupz(name, namelen);
|
||||
pp->e.name = xmemdupz(name, namelen);
|
||||
pp->next = funcname_pattern_list;
|
||||
funcname_pattern_list = pp;
|
||||
}
|
||||
free(pp->pattern);
|
||||
pp->pattern = xstrdup(value);
|
||||
free(pp->e.pattern);
|
||||
pp->e.pattern = xstrdup(value);
|
||||
pp->e.cflags = cflags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -194,7 +199,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
|
||||
if (!strcmp(ep, ".funcname")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
return parse_funcname_pattern(var, ep, value);
|
||||
return parse_funcname_pattern(var, ep, value,
|
||||
0);
|
||||
} else if (!strcmp(ep, ".xfuncname")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
return parse_funcname_pattern(var, ep, value,
|
||||
REG_EXTENDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1131,9 +1142,13 @@ static void show_dirstat(struct diff_options *options)
|
||||
/*
|
||||
* Original minus copied is the removed material,
|
||||
* added is the new material. They are both damages
|
||||
* made to the preimage.
|
||||
* made to the preimage. In --dirstat-by-file mode, count
|
||||
* damaged files, not damaged lines. This is done by
|
||||
* counting only a single damaged line per file.
|
||||
*/
|
||||
damage = (p->one->size - copied) + added;
|
||||
if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0)
|
||||
damage = 1;
|
||||
|
||||
ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
|
||||
dir.files[dir.nr].name = name;
|
||||
@@ -1396,42 +1411,53 @@ int diff_filespec_is_binary(struct diff_filespec *one)
|
||||
return one->is_binary;
|
||||
}
|
||||
|
||||
static const char *funcname_pattern(const char *ident)
|
||||
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
|
||||
{
|
||||
struct funcname_pattern *pp;
|
||||
struct funcname_pattern_list *pp;
|
||||
|
||||
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
||||
if (!strcmp(ident, pp->name))
|
||||
return pp->pattern;
|
||||
if (!strcmp(ident, pp->e.name))
|
||||
return &pp->e;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct builtin_funcname_pattern {
|
||||
const char *name;
|
||||
const char *pattern;
|
||||
} builtin_funcname_pattern[] = {
|
||||
{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" },
|
||||
{ "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" },
|
||||
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
|
||||
"new\\|return\\|switch\\|throw\\|while\\)\n"
|
||||
"^[ ]*\\(\\([ ]*"
|
||||
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
|
||||
"[ ]*([^;]*\\)$" },
|
||||
{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
|
||||
"destructor\\|interface\\|implementation\\|"
|
||||
"initialization\\|finalization\\)[ \t]*.*\\)$"
|
||||
"\\|"
|
||||
"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
|
||||
},
|
||||
{ "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" },
|
||||
{ "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" },
|
||||
{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" },
|
||||
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
|
||||
static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
|
||||
{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
|
||||
REG_EXTENDED },
|
||||
{ "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED },
|
||||
{ "java",
|
||||
"!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
|
||||
"^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
|
||||
REG_EXTENDED },
|
||||
{ "objc",
|
||||
/* Negate C statements that can look like functions */
|
||||
"!^[ \t]*(do|for|if|else|return|switch|while)\n"
|
||||
/* Objective-C methods */
|
||||
"^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n"
|
||||
/* C functions */
|
||||
"^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n"
|
||||
/* Objective-C class/protocol definitions */
|
||||
"^(@(implementation|interface|protocol)[ \t].*)$",
|
||||
REG_EXTENDED },
|
||||
{ "pascal",
|
||||
"^((procedure|function|constructor|destructor|interface|"
|
||||
"implementation|initialization|finalization)[ \t]*.*)$"
|
||||
"\n"
|
||||
"^(.*=[ \t]*(class|record).*)$",
|
||||
REG_EXTENDED },
|
||||
{ "php", "^[\t ]*((function|class).*)", REG_EXTENDED },
|
||||
{ "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED },
|
||||
{ "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
|
||||
REG_EXTENDED },
|
||||
{ "tex",
|
||||
"^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
|
||||
REG_EXTENDED },
|
||||
};
|
||||
|
||||
static const char *diff_funcname_pattern(struct diff_filespec *one)
|
||||
static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
|
||||
{
|
||||
const char *ident, *pattern;
|
||||
const char *ident;
|
||||
const struct funcname_pattern_entry *pe;
|
||||
int i;
|
||||
|
||||
diff_filespec_check_attr(one);
|
||||
@@ -1446,9 +1472,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
|
||||
return funcname_pattern("default");
|
||||
|
||||
/* Look up custom "funcname.$ident" regexp from config. */
|
||||
pattern = funcname_pattern(ident);
|
||||
if (pattern)
|
||||
return pattern;
|
||||
pe = funcname_pattern(ident);
|
||||
if (pe)
|
||||
return pe;
|
||||
|
||||
/*
|
||||
* And define built-in fallback patterns here. Note that
|
||||
@@ -1456,7 +1482,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
|
||||
if (!strcmp(ident, builtin_funcname_pattern[i].name))
|
||||
return builtin_funcname_pattern[i].pattern;
|
||||
return &builtin_funcname_pattern[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1493,6 +1519,10 @@ static void builtin_diff(const char *name_a,
|
||||
b_prefix = o->b_prefix;
|
||||
}
|
||||
|
||||
/* Never use a non-valid filename anywhere if at all possible */
|
||||
name_a = DIFF_FILE_VALID(one) ? name_a : name_b;
|
||||
name_b = DIFF_FILE_VALID(two) ? name_b : name_a;
|
||||
|
||||
a_one = quote_two(a_prefix, name_a + (*name_a == '/'));
|
||||
b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
|
||||
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
|
||||
@@ -1552,11 +1582,11 @@ static void builtin_diff(const char *name_a,
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
struct emit_callback ecbdata;
|
||||
const char *funcname_pattern;
|
||||
const struct funcname_pattern_entry *pe;
|
||||
|
||||
funcname_pattern = diff_funcname_pattern(one);
|
||||
if (!funcname_pattern)
|
||||
funcname_pattern = diff_funcname_pattern(two);
|
||||
pe = diff_funcname_pattern(one);
|
||||
if (!pe)
|
||||
pe = diff_funcname_pattern(two);
|
||||
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
memset(&ecbdata, 0, sizeof(ecbdata));
|
||||
@@ -1568,8 +1598,8 @@ static void builtin_diff(const char *name_a,
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xecfg.ctxlen = o->context;
|
||||
xecfg.flags = XDL_EMIT_FUNCNAMES;
|
||||
if (funcname_pattern)
|
||||
xdiff_set_find_func(&xecfg, funcname_pattern);
|
||||
if (pe)
|
||||
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
|
||||
if (!diffopts)
|
||||
;
|
||||
else if (!prefixcmp(diffopts, "--unified="))
|
||||
@@ -2511,6 +2541,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
||||
else if (!strcmp(arg, "--cumulative")) {
|
||||
options->output_format |= DIFF_FORMAT_DIRSTAT;
|
||||
DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
|
||||
} else if (opt_arg(arg, 0, "dirstat-by-file",
|
||||
&options->dirstat_percent)) {
|
||||
options->output_format |= DIFF_FORMAT_DIRSTAT;
|
||||
DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
|
||||
}
|
||||
else if (!strcmp(arg, "--check"))
|
||||
options->output_format |= DIFF_FORMAT_CHECKDIFF;
|
||||
@@ -3067,7 +3101,7 @@ static void diff_summary(FILE *file, struct diff_filepair *p)
|
||||
}
|
||||
|
||||
struct patch_id_t {
|
||||
SHA_CTX *ctx;
|
||||
git_SHA_CTX *ctx;
|
||||
int patchlen;
|
||||
};
|
||||
|
||||
@@ -3095,7 +3129,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
|
||||
|
||||
new_len = remove_space(line, len);
|
||||
|
||||
SHA1_Update(data->ctx, line, new_len);
|
||||
git_SHA1_Update(data->ctx, line, new_len);
|
||||
data->patchlen += new_len;
|
||||
}
|
||||
|
||||
@@ -3104,11 +3138,11 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
{
|
||||
struct diff_queue_struct *q = &diff_queued_diff;
|
||||
int i;
|
||||
SHA_CTX ctx;
|
||||
git_SHA_CTX ctx;
|
||||
struct patch_id_t data;
|
||||
char buffer[PATH_MAX * 4 + 20];
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
git_SHA1_Init(&ctx);
|
||||
memset(&data, 0, sizeof(struct patch_id_t));
|
||||
data.ctx = &ctx;
|
||||
|
||||
@@ -3170,7 +3204,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
len2, p->two->path,
|
||||
len1, p->one->path,
|
||||
len2, p->two->path);
|
||||
SHA1_Update(&ctx, buffer, len1);
|
||||
git_SHA1_Update(&ctx, buffer, len1);
|
||||
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
xecfg.ctxlen = 3;
|
||||
@@ -3179,7 +3213,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
&xpp, &xecfg, &ecb);
|
||||
}
|
||||
|
||||
SHA1_Final(sha1, &ctx);
|
||||
git_SHA1_Final(sha1, &ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
1
diff.h
1
diff.h
@@ -64,6 +64,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
||||
#define DIFF_OPT_RELATIVE_NAME (1 << 17)
|
||||
#define DIFF_OPT_IGNORE_SUBMODULES (1 << 18)
|
||||
#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19)
|
||||
#define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20)
|
||||
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
|
||||
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
|
||||
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
|
||||
|
||||
24
dir.c
24
dir.c
@@ -382,7 +382,7 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)
|
||||
return ent;
|
||||
}
|
||||
|
||||
struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
|
||||
static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
|
||||
{
|
||||
if (cache_name_exists(pathname, len, ignore_case))
|
||||
return NULL;
|
||||
@@ -391,7 +391,7 @@ struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int
|
||||
return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
|
||||
}
|
||||
|
||||
struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
|
||||
static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
|
||||
{
|
||||
if (cache_name_pos(pathname, len) >= 0)
|
||||
return NULL;
|
||||
@@ -831,3 +831,23 @@ void setup_standard_excludes(struct dir_struct *dir)
|
||||
if (excludes_file && !access(excludes_file, R_OK))
|
||||
add_excludes_from_file(dir, excludes_file);
|
||||
}
|
||||
|
||||
int remove_path(const char *name)
|
||||
{
|
||||
char *slash;
|
||||
|
||||
if (unlink(name) && errno != ENOENT)
|
||||
return -1;
|
||||
|
||||
slash = strrchr(name, '/');
|
||||
if (slash) {
|
||||
char *dirs = xstrdup(name);
|
||||
slash = dirs + (slash - name);
|
||||
do {
|
||||
*slash = '\0';
|
||||
} while (rmdir(dirs) && (slash = strrchr(dirs, '/')));
|
||||
free(dirs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
4
dir.h
4
dir.h
@@ -73,7 +73,6 @@ extern void add_excludes_from_file(struct dir_struct *, const char *fname);
|
||||
extern void add_exclude(const char *string, const char *base,
|
||||
int baselen, struct exclude_list *which);
|
||||
extern int file_exists(const char *);
|
||||
extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len);
|
||||
|
||||
extern char *get_relative_cwd(char *buffer, int size, const char *dir);
|
||||
extern int is_inside_dir(const char *dir);
|
||||
@@ -81,4 +80,7 @@ extern int is_inside_dir(const char *dir);
|
||||
extern void setup_standard_excludes(struct dir_struct *dir);
|
||||
extern int remove_dir_recursively(struct strbuf *path, int only_empty);
|
||||
|
||||
/* tries to remove the path with empty directories along it, ignores ENOENT */
|
||||
extern int remove_path(const char *path);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -80,6 +80,11 @@ int is_bare_repository(void)
|
||||
return is_bare_repository_cfg && !get_git_work_tree();
|
||||
}
|
||||
|
||||
int have_git_dir(void)
|
||||
{
|
||||
return !!git_dir;
|
||||
}
|
||||
|
||||
const char *get_git_dir(void)
|
||||
{
|
||||
if (!git_dir)
|
||||
|
||||
@@ -816,7 +816,7 @@ static void start_packfile(void)
|
||||
int pack_fd;
|
||||
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_pack_XXXXXX", get_object_directory());
|
||||
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
|
||||
pack_fd = xmkstemp(tmpfile);
|
||||
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
|
||||
strcpy(p->pack_name, tmpfile);
|
||||
@@ -845,7 +845,7 @@ static int oecmp (const void *a_, const void *b_)
|
||||
static char *create_index(void)
|
||||
{
|
||||
static char tmpfile[PATH_MAX];
|
||||
SHA_CTX ctx;
|
||||
git_SHA_CTX ctx;
|
||||
struct sha1file *f;
|
||||
struct object_entry **idx, **c, **last, *e;
|
||||
struct object_entry_pool *o;
|
||||
@@ -878,21 +878,21 @@ static char *create_index(void)
|
||||
}
|
||||
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_idx_XXXXXX", get_object_directory());
|
||||
"%s/pack/tmp_idx_XXXXXX", get_object_directory());
|
||||
idx_fd = xmkstemp(tmpfile);
|
||||
f = sha1fd(idx_fd, tmpfile);
|
||||
sha1write(f, array, 256 * sizeof(int));
|
||||
SHA1_Init(&ctx);
|
||||
git_SHA1_Init(&ctx);
|
||||
for (c = idx; c != last; c++) {
|
||||
uint32_t offset = htonl((*c)->offset);
|
||||
sha1write(f, &offset, 4);
|
||||
sha1write(f, (*c)->sha1, sizeof((*c)->sha1));
|
||||
SHA1_Update(&ctx, (*c)->sha1, 20);
|
||||
git_SHA1_Update(&ctx, (*c)->sha1, 20);
|
||||
}
|
||||
sha1write(f, pack_data->sha1, sizeof(pack_data->sha1));
|
||||
sha1close(f, NULL, CSUM_FSYNC);
|
||||
free(idx);
|
||||
SHA1_Final(pack_data->sha1, &ctx);
|
||||
git_SHA1_Final(pack_data->sha1, &ctx);
|
||||
return tmpfile;
|
||||
}
|
||||
|
||||
@@ -1033,15 +1033,15 @@ static int store_object(
|
||||
unsigned char hdr[96];
|
||||
unsigned char sha1[20];
|
||||
unsigned long hdrlen, deltalen;
|
||||
SHA_CTX c;
|
||||
git_SHA_CTX c;
|
||||
z_stream s;
|
||||
|
||||
hdrlen = sprintf((char*)hdr,"%s %lu", typename(type),
|
||||
(unsigned long)dat->len) + 1;
|
||||
SHA1_Init(&c);
|
||||
SHA1_Update(&c, hdr, hdrlen);
|
||||
SHA1_Update(&c, dat->buf, dat->len);
|
||||
SHA1_Final(sha1, &c);
|
||||
git_SHA1_Init(&c);
|
||||
git_SHA1_Update(&c, hdr, hdrlen);
|
||||
git_SHA1_Update(&c, dat->buf, dat->len);
|
||||
git_SHA1_Final(sha1, &c);
|
||||
if (sha1out)
|
||||
hashcpy(sha1out, sha1);
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
#undef _XOPEN_SOURCE
|
||||
#include <grp.h>
|
||||
#define _XOPEN_SOURCE 600
|
||||
#include "compat/cygwin.h"
|
||||
#else
|
||||
#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
|
||||
#include <grp.h>
|
||||
@@ -154,10 +155,7 @@ extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1,
|
||||
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
extern void set_usage_routine(void (*routine)(const char *err) NORETURN);
|
||||
extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
|
||||
extern void set_error_routine(void (*routine)(const char *err, va_list params));
|
||||
extern void set_warn_routine(void (*routine)(const char *warn, va_list params));
|
||||
|
||||
extern int prefixcmp(const char *str, const char *prefix);
|
||||
extern time_t tm_to_time_t(const struct tm *tm);
|
||||
|
||||
3
git-gui/.gitattributes
vendored
Normal file
3
git-gui/.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
* encoding=US-ASCII
|
||||
git-gui.sh encoding=UTF-8
|
||||
/po/*.po encoding=UTF-8
|
||||
@@ -521,6 +521,19 @@ proc kill_file_process {fd} {
|
||||
}
|
||||
}
|
||||
|
||||
proc gitattr {path attr default} {
|
||||
if {[catch {set r [git check-attr $attr -- $path]}]} {
|
||||
set r unspecified
|
||||
} else {
|
||||
set r [join [lrange [split $r :] 2 end] :]
|
||||
regsub {^ } $r {} r
|
||||
}
|
||||
if {$r eq {unspecified}} {
|
||||
return $default
|
||||
}
|
||||
return $r
|
||||
}
|
||||
|
||||
proc sq {value} {
|
||||
regsub -all ' $value "'\\''" value
|
||||
return "'$value'"
|
||||
@@ -665,6 +678,7 @@ set default_config(merge.verbosity) 2
|
||||
set default_config(user.name) {}
|
||||
set default_config(user.email) {}
|
||||
|
||||
set default_config(gui.encoding) [encoding system]
|
||||
set default_config(gui.matchtrackingbranch) false
|
||||
set default_config(gui.pruneduringfetch) false
|
||||
set default_config(gui.trustmtime) false
|
||||
@@ -948,10 +962,32 @@ blame {
|
||||
}
|
||||
citool {
|
||||
enable_option singlecommit
|
||||
enable_option retcode
|
||||
|
||||
disable_option multicommit
|
||||
disable_option branch
|
||||
disable_option transport
|
||||
|
||||
while {[llength $argv] > 0} {
|
||||
set a [lindex $argv 0]
|
||||
switch -- $a {
|
||||
--amend {
|
||||
enable_option initialamend
|
||||
}
|
||||
--nocommit {
|
||||
enable_option nocommit
|
||||
enable_option nocommitmsg
|
||||
}
|
||||
--commitmsg {
|
||||
disable_option nocommitmsg
|
||||
}
|
||||
default {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
set argv [lrange $argv 1 end]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1023,8 +1059,12 @@ set current_branch {}
|
||||
set is_detached 0
|
||||
set current_diff_path {}
|
||||
set is_3way_diff 0
|
||||
set is_conflict_diff 0
|
||||
set selected_commit_type new
|
||||
|
||||
set nullid "0000000000000000000000000000000000000000"
|
||||
set nullid2 "0000000000000000000000000000000000000001"
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## task management
|
||||
@@ -1105,6 +1145,20 @@ proc PARENT {} {
|
||||
return $empty_tree
|
||||
}
|
||||
|
||||
proc force_amend {} {
|
||||
global selected_commit_type
|
||||
global HEAD PARENT MERGE_HEAD commit_type
|
||||
|
||||
repository_state newType newHEAD newMERGE_HEAD
|
||||
set HEAD $newHEAD
|
||||
set PARENT $newHEAD
|
||||
set MERGE_HEAD $newMERGE_HEAD
|
||||
set commit_type $newType
|
||||
|
||||
set selected_commit_type amend
|
||||
do_select_commit_type
|
||||
}
|
||||
|
||||
proc rescan {after {honor_trustmtime 1}} {
|
||||
global HEAD PARENT MERGE_HEAD commit_type
|
||||
global ui_index ui_workdir ui_comm
|
||||
@@ -1131,6 +1185,7 @@ proc rescan {after {honor_trustmtime 1}} {
|
||||
|| [string trim [$ui_comm get 0.0 end]] eq {})} {
|
||||
if {[string match amend* $commit_type]} {
|
||||
} elseif {[load_message GITGUI_MSG]} {
|
||||
} elseif {[run_prepare_commit_msg_hook]} {
|
||||
} elseif {[load_message MERGE_MSG]} {
|
||||
} elseif {[load_message SQUASH_MSG]} {
|
||||
}
|
||||
@@ -1230,6 +1285,70 @@ proc load_message {file} {
|
||||
return 0
|
||||
}
|
||||
|
||||
proc run_prepare_commit_msg_hook {} {
|
||||
global pch_error
|
||||
|
||||
# prepare-commit-msg requires PREPARE_COMMIT_MSG exist. From git-gui
|
||||
# it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
|
||||
# empty file but existant file.
|
||||
|
||||
set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
|
||||
|
||||
if {[file isfile [gitdir MERGE_MSG]]} {
|
||||
set pcm_source "merge"
|
||||
set fd_mm [open [gitdir MERGE_MSG] r]
|
||||
puts -nonewline $fd_pcm [read $fd_mm]
|
||||
close $fd_mm
|
||||
} elseif {[file isfile [gitdir SQUASH_MSG]]} {
|
||||
set pcm_source "squash"
|
||||
set fd_sm [open [gitdir SQUASH_MSG] r]
|
||||
puts -nonewline $fd_pcm [read $fd_sm]
|
||||
close $fd_sm
|
||||
} else {
|
||||
set pcm_source ""
|
||||
}
|
||||
|
||||
close $fd_pcm
|
||||
|
||||
set fd_ph [githook_read prepare-commit-msg \
|
||||
[gitdir PREPARE_COMMIT_MSG] $pcm_source]
|
||||
if {$fd_ph eq {}} {
|
||||
catch {file delete [gitdir PREPARE_COMMIT_MSG]}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ui_status [mc "Calling prepare-commit-msg hook..."]
|
||||
set pch_error {}
|
||||
|
||||
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
|
||||
fileevent $fd_ph readable \
|
||||
[list prepare_commit_msg_hook_wait $fd_ph]
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
proc prepare_commit_msg_hook_wait {fd_ph} {
|
||||
global pch_error
|
||||
|
||||
append pch_error [read $fd_ph]
|
||||
fconfigure $fd_ph -blocking 1
|
||||
if {[eof $fd_ph]} {
|
||||
if {[catch {close $fd_ph}]} {
|
||||
ui_status [mc "Commit declined by prepare-commit-msg hook."]
|
||||
hook_failed_popup prepare-commit-msg $pch_error
|
||||
catch {file delete [gitdir PREPARE_COMMIT_MSG]}
|
||||
exit 1
|
||||
} else {
|
||||
load_message PREPARE_COMMIT_MSG
|
||||
}
|
||||
set pch_error {}
|
||||
catch {file delete [gitdir PREPARE_COMMIT_MSG]}
|
||||
return
|
||||
}
|
||||
fconfigure $fd_ph -blocking 0
|
||||
catch {file delete [gitdir PREPARE_COMMIT_MSG]}
|
||||
}
|
||||
|
||||
proc read_diff_index {fd after} {
|
||||
global buf_rdi
|
||||
|
||||
@@ -1751,11 +1870,19 @@ proc do_gitk {revs} {
|
||||
}
|
||||
|
||||
set is_quitting 0
|
||||
set ret_code 1
|
||||
|
||||
proc do_quit {} {
|
||||
proc terminate_me {win} {
|
||||
global ret_code
|
||||
if {$win ne {.}} return
|
||||
exit $ret_code
|
||||
}
|
||||
|
||||
proc do_quit {{rc {1}}} {
|
||||
global ui_comm is_quitting repo_config commit_type
|
||||
global GITGUI_BCK_exists GITGUI_BCK_i
|
||||
global ui_comm_spell
|
||||
global ret_code
|
||||
|
||||
if {$is_quitting} return
|
||||
set is_quitting 1
|
||||
@@ -1810,6 +1937,7 @@ proc do_quit {} {
|
||||
}
|
||||
}
|
||||
|
||||
set ret_code $rc
|
||||
destroy .
|
||||
}
|
||||
|
||||
@@ -1951,19 +2079,21 @@ proc toggle_or_diff {w x y} {
|
||||
$ui_index tag remove in_sel 0.0 end
|
||||
$ui_workdir tag remove in_sel 0.0 end
|
||||
|
||||
# Do not stage files with conflicts
|
||||
# Determine the state of the file
|
||||
if {[info exists file_states($path)]} {
|
||||
set state [lindex $file_states($path) 0]
|
||||
} else {
|
||||
set state {__}
|
||||
}
|
||||
|
||||
if {[string first {U} $state] >= 0} {
|
||||
set col 1
|
||||
}
|
||||
|
||||
# Restage the file, or simply show the diff
|
||||
if {$col == 0 && $y > 1} {
|
||||
# Conflicts need special handling
|
||||
if {[string first {U} $state] >= 0} {
|
||||
merge_stage_workdir $path $w $lno
|
||||
return
|
||||
}
|
||||
|
||||
if {[string index $state 1] eq {O}} {
|
||||
set mmask {}
|
||||
} else {
|
||||
@@ -2212,26 +2342,36 @@ if {[is_enabled branch]} {
|
||||
|
||||
# -- Commit Menu
|
||||
#
|
||||
proc commit_btn_caption {} {
|
||||
if {[is_enabled nocommit]} {
|
||||
return [mc "Done"]
|
||||
} else {
|
||||
return [mc Commit@@verb]
|
||||
}
|
||||
}
|
||||
|
||||
if {[is_enabled multicommit] || [is_enabled singlecommit]} {
|
||||
menu .mbar.commit
|
||||
|
||||
.mbar.commit add radiobutton \
|
||||
-label [mc "New Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value new
|
||||
lappend disable_on_lock \
|
||||
[list .mbar.commit entryconf [.mbar.commit index last] -state]
|
||||
if {![is_enabled nocommit]} {
|
||||
.mbar.commit add radiobutton \
|
||||
-label [mc "New Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value new
|
||||
lappend disable_on_lock \
|
||||
[list .mbar.commit entryconf [.mbar.commit index last] -state]
|
||||
|
||||
.mbar.commit add radiobutton \
|
||||
-label [mc "Amend Last Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value amend
|
||||
lappend disable_on_lock \
|
||||
[list .mbar.commit entryconf [.mbar.commit index last] -state]
|
||||
.mbar.commit add radiobutton \
|
||||
-label [mc "Amend Last Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value amend
|
||||
lappend disable_on_lock \
|
||||
[list .mbar.commit entryconf [.mbar.commit index last] -state]
|
||||
|
||||
.mbar.commit add separator
|
||||
.mbar.commit add separator
|
||||
}
|
||||
|
||||
.mbar.commit add command -label [mc Rescan] \
|
||||
-command ui_do_rescan \
|
||||
@@ -2273,11 +2413,13 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
|
||||
|
||||
.mbar.commit add separator
|
||||
|
||||
.mbar.commit add command -label [mc "Sign Off"] \
|
||||
-command do_signoff \
|
||||
-accelerator $M1T-S
|
||||
if {![is_enabled nocommit]} {
|
||||
.mbar.commit add command -label [mc "Sign Off"] \
|
||||
-command do_signoff \
|
||||
-accelerator $M1T-S
|
||||
}
|
||||
|
||||
.mbar.commit add command -label [mc Commit@@verb] \
|
||||
.mbar.commit add command -label [commit_btn_caption] \
|
||||
-command do_commit \
|
||||
-accelerator $M1T-Return
|
||||
lappend disable_on_lock \
|
||||
@@ -2601,19 +2743,23 @@ pack .vpane.lower.commarea.buttons.incall -side top -fill x
|
||||
lappend disable_on_lock \
|
||||
{.vpane.lower.commarea.buttons.incall conf -state}
|
||||
|
||||
button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \
|
||||
-command do_signoff
|
||||
pack .vpane.lower.commarea.buttons.signoff -side top -fill x
|
||||
if {![is_enabled nocommit]} {
|
||||
button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \
|
||||
-command do_signoff
|
||||
pack .vpane.lower.commarea.buttons.signoff -side top -fill x
|
||||
}
|
||||
|
||||
button .vpane.lower.commarea.buttons.commit -text [mc Commit@@verb] \
|
||||
button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \
|
||||
-command do_commit
|
||||
pack .vpane.lower.commarea.buttons.commit -side top -fill x
|
||||
lappend disable_on_lock \
|
||||
{.vpane.lower.commarea.buttons.commit conf -state}
|
||||
|
||||
button .vpane.lower.commarea.buttons.push -text [mc Push] \
|
||||
-command do_push_anywhere
|
||||
pack .vpane.lower.commarea.buttons.push -side top -fill x
|
||||
if {![is_enabled nocommit]} {
|
||||
button .vpane.lower.commarea.buttons.push -text [mc Push] \
|
||||
-command do_push_anywhere
|
||||
pack .vpane.lower.commarea.buttons.push -side top -fill x
|
||||
}
|
||||
|
||||
# -- Commit Message Buffer
|
||||
#
|
||||
@@ -2621,20 +2767,24 @@ frame .vpane.lower.commarea.buffer
|
||||
frame .vpane.lower.commarea.buffer.header
|
||||
set ui_comm .vpane.lower.commarea.buffer.t
|
||||
set ui_coml .vpane.lower.commarea.buffer.header.l
|
||||
radiobutton .vpane.lower.commarea.buffer.header.new \
|
||||
-text [mc "New Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value new
|
||||
lappend disable_on_lock \
|
||||
[list .vpane.lower.commarea.buffer.header.new conf -state]
|
||||
radiobutton .vpane.lower.commarea.buffer.header.amend \
|
||||
-text [mc "Amend Last Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value amend
|
||||
lappend disable_on_lock \
|
||||
[list .vpane.lower.commarea.buffer.header.amend conf -state]
|
||||
|
||||
if {![is_enabled nocommit]} {
|
||||
radiobutton .vpane.lower.commarea.buffer.header.new \
|
||||
-text [mc "New Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value new
|
||||
lappend disable_on_lock \
|
||||
[list .vpane.lower.commarea.buffer.header.new conf -state]
|
||||
radiobutton .vpane.lower.commarea.buffer.header.amend \
|
||||
-text [mc "Amend Last Commit"] \
|
||||
-command do_select_commit_type \
|
||||
-variable selected_commit_type \
|
||||
-value amend
|
||||
lappend disable_on_lock \
|
||||
[list .vpane.lower.commarea.buffer.header.amend conf -state]
|
||||
}
|
||||
|
||||
label $ui_coml \
|
||||
-anchor w \
|
||||
-justify left
|
||||
@@ -2652,8 +2802,11 @@ proc trace_commit_type {varname args} {
|
||||
}
|
||||
trace add variable commit_type write trace_commit_type
|
||||
pack $ui_coml -side left -fill x
|
||||
pack .vpane.lower.commarea.buffer.header.amend -side right
|
||||
pack .vpane.lower.commarea.buffer.header.new -side right
|
||||
|
||||
if {![is_enabled nocommit]} {
|
||||
pack .vpane.lower.commarea.buffer.header.amend -side right
|
||||
pack .vpane.lower.commarea.buffer.header.new -side right
|
||||
}
|
||||
|
||||
text $ui_comm -background white -foreground black \
|
||||
-borderwidth 1 \
|
||||
@@ -2860,6 +3013,14 @@ proc create_common_diff_popup {ctxm} {
|
||||
-command {incr_font_size font_diff 1}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
set emenu $ctxm.enc
|
||||
menu $emenu
|
||||
build_encoding_menu $emenu [list force_diff_encoding]
|
||||
$ctxm add cascade \
|
||||
-label [mc "Encoding"] \
|
||||
-menu $emenu
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command -label [mc "Options..."] \
|
||||
-command do_options
|
||||
}
|
||||
@@ -3191,7 +3352,20 @@ lock_index begin-read
|
||||
if {![winfo ismapped .]} {
|
||||
wm deiconify .
|
||||
}
|
||||
after 1 do_rescan
|
||||
after 1 {
|
||||
if {[is_enabled initialamend]} {
|
||||
force_amend
|
||||
} else {
|
||||
do_rescan
|
||||
}
|
||||
|
||||
if {[is_enabled nocommitmsg]} {
|
||||
$ui_comm configure -state disabled -background gray
|
||||
}
|
||||
}
|
||||
if {[is_enabled multicommit]} {
|
||||
after 1000 hint_gc
|
||||
}
|
||||
if {[is_enabled retcode]} {
|
||||
bind . <Destroy> {+terminate_me %W}
|
||||
}
|
||||
|
||||
@@ -256,9 +256,16 @@ constructor new {i_commit i_path i_jump} {
|
||||
$w.ctxm add command \
|
||||
-label [mc "Copy Commit"] \
|
||||
-command [cb _copycommit]
|
||||
$w.ctxm add separator
|
||||
menu $w.ctxm.enc
|
||||
build_encoding_menu $w.ctxm.enc [cb _setencoding]
|
||||
$w.ctxm add cascade \
|
||||
-label [mc "Encoding"] \
|
||||
-menu $w.ctxm.enc
|
||||
$w.ctxm add command \
|
||||
-label [mc "Do Full Copy Detection"] \
|
||||
-command [cb _fullcopyblame]
|
||||
$w.ctxm add separator
|
||||
$w.ctxm add command \
|
||||
-label [mc "Show History Context"] \
|
||||
-command [cb _gitkcommit]
|
||||
@@ -399,7 +406,10 @@ method _load {jump} {
|
||||
} else {
|
||||
set fd [git_read cat-file blob "$commit:$path"]
|
||||
}
|
||||
fconfigure $fd -blocking 0 -translation lf -encoding binary
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-translation lf \
|
||||
-encoding [get_path_encoding $path]
|
||||
fileevent $fd readable [cb _read_file $fd $jump]
|
||||
set current_fd $fd
|
||||
}
|
||||
@@ -508,7 +518,7 @@ method _exec_blame {cur_w cur_d options cur_s} {
|
||||
}
|
||||
lappend options -- $path
|
||||
set fd [eval git_read --nice blame $options]
|
||||
fconfigure $fd -blocking 0 -translation lf -encoding binary
|
||||
fconfigure $fd -blocking 0 -translation lf -encoding utf-8
|
||||
fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
|
||||
set current_fd $fd
|
||||
set blame_lines 0
|
||||
@@ -788,6 +798,16 @@ method _click {cur_w pos} {
|
||||
_showcommit $this $cur_w $lno
|
||||
}
|
||||
|
||||
method _setencoding {enc} {
|
||||
force_path_encoding $path $enc
|
||||
_load $this [list \
|
||||
$highlight_column \
|
||||
$highlight_line \
|
||||
[lindex [$w_file xview] 0] \
|
||||
[lindex [$w_file yview] 0] \
|
||||
]
|
||||
}
|
||||
|
||||
method _load_commit {cur_w cur_d pos} {
|
||||
upvar #0 $cur_d line_data
|
||||
set lno [lindex [split [$cur_w index $pos] .] 0]
|
||||
@@ -881,12 +901,6 @@ method _showcommit {cur_w lno} {
|
||||
set enc [tcl_encoding $enc]
|
||||
if {$enc ne {}} {
|
||||
set msg [encoding convertfrom $enc $msg]
|
||||
set author_name [encoding convertfrom $enc $author_name]
|
||||
set committer_name [encoding convertfrom $enc $committer_name]
|
||||
set header($cmit,author) $author_name
|
||||
set header($cmit,committer) $committer_name
|
||||
set header($cmit,summary) \
|
||||
[encoding convertfrom $enc $header($cmit,summary)]
|
||||
}
|
||||
set msg [string trim $msg]
|
||||
}
|
||||
@@ -942,9 +956,20 @@ method _format_offset_date {base offset} {
|
||||
}
|
||||
|
||||
method _gitkcommit {} {
|
||||
global nullid
|
||||
|
||||
set dat [_get_click_amov_info $this]
|
||||
if {$dat ne {}} {
|
||||
set cmit [lindex $dat 0]
|
||||
|
||||
# If the line belongs to the working copy, use HEAD instead
|
||||
if {$cmit eq $nullid} {
|
||||
if {[catch {set cmit [git rev-parse --verify HEAD]} err]} {
|
||||
error_popup [strcat [mc "Cannot find HEAD commit:"] "\n\n$err"]
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
set radius [get_config gui.blamehistoryctx]
|
||||
set cmdline [list --select-commit=$cmit]
|
||||
|
||||
@@ -981,12 +1006,20 @@ method _gitkcommit {} {
|
||||
}
|
||||
|
||||
method _blameparent {} {
|
||||
global nullid
|
||||
|
||||
set dat [_get_click_amov_info $this]
|
||||
if {$dat ne {}} {
|
||||
set cmit [lindex $dat 0]
|
||||
set new_path [lindex $dat 1]
|
||||
|
||||
if {[catch {set cparent [git rev-parse --verify "$cmit^"]}]} {
|
||||
# Allow using Blame Parent on lines modified in the working copy
|
||||
if {$cmit eq $nullid} {
|
||||
set parent_ref "HEAD"
|
||||
} else {
|
||||
set parent_ref "$cmit^"
|
||||
}
|
||||
if {[catch {set cparent [git rev-parse --verify $parent_ref]} err]} {
|
||||
error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"]
|
||||
return;
|
||||
}
|
||||
@@ -996,8 +1029,12 @@ method _blameparent {} {
|
||||
# Generate a diff between the commit and its parent,
|
||||
# and use the hunks to update the line number.
|
||||
# Request zero context to simplify calculations.
|
||||
if {[catch {set fd [eval git_read diff-tree \
|
||||
--unified=0 $cparent $cmit $new_path]} err]} {
|
||||
if {$cmit eq $nullid} {
|
||||
set diffcmd [list diff-index --unified=0 $cparent -- $new_path]
|
||||
} else {
|
||||
set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path]
|
||||
}
|
||||
if {[catch {set fd [eval git_read $diffcmd]} err]} {
|
||||
$status stop [mc "Unable to display parent"]
|
||||
error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
|
||||
return
|
||||
|
||||
@@ -168,7 +168,7 @@ File %s cannot be committed by this program.
|
||||
}
|
||||
}
|
||||
}
|
||||
if {!$files_ready && ![string match *merge $curType]} {
|
||||
if {!$files_ready && ![string match *merge $curType] && ![is_enabled nocommit]} {
|
||||
info_popup [mc "No changes to commit.
|
||||
|
||||
You must stage at least 1 file before you can commit.
|
||||
@@ -177,6 +177,8 @@ You must stage at least 1 file before you can commit.
|
||||
return
|
||||
}
|
||||
|
||||
if {[is_enabled nocommitmsg]} { do_quit 0 }
|
||||
|
||||
# -- A message is required.
|
||||
#
|
||||
set msg [string trim [$ui_comm get 1.0 end]]
|
||||
@@ -212,6 +214,8 @@ A good commit message has the following format:
|
||||
puts $msg_wt $msg
|
||||
close $msg_wt
|
||||
|
||||
if {[is_enabled nocommit]} { do_quit 0 }
|
||||
|
||||
# -- Run the pre-commit hook.
|
||||
#
|
||||
set fd_ph [githook_read pre-commit]
|
||||
@@ -410,7 +414,7 @@ A rescan will be automatically started now.
|
||||
set ::GITGUI_BCK_exists 0
|
||||
}
|
||||
|
||||
if {[is_enabled singlecommit]} do_quit
|
||||
if {[is_enabled singlecommit]} { do_quit 0 }
|
||||
|
||||
# -- Update in memory status
|
||||
#
|
||||
|
||||
@@ -40,6 +40,15 @@ proc reshow_diff {} {
|
||||
}
|
||||
}
|
||||
|
||||
proc force_diff_encoding {enc} {
|
||||
global current_diff_path
|
||||
|
||||
if {$current_diff_path ne {}} {
|
||||
force_path_encoding $current_diff_path $enc
|
||||
reshow_diff
|
||||
}
|
||||
}
|
||||
|
||||
proc handle_empty_diff {} {
|
||||
global current_diff_path file_states file_lists
|
||||
|
||||
@@ -60,9 +69,9 @@ A rescan will be automatically started to find other files which may have the sa
|
||||
rescan ui_ready 0
|
||||
}
|
||||
|
||||
proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} {
|
||||
global file_states file_lists
|
||||
global is_3way_diff diff_active repo_config
|
||||
global is_3way_diff is_conflict_diff diff_active repo_config
|
||||
global ui_diff ui_index ui_workdir
|
||||
global current_diff_path current_diff_side current_diff_header
|
||||
global current_diff_queue
|
||||
@@ -83,36 +92,42 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
|
||||
set s $file_states($path)
|
||||
set m [lindex $s 0]
|
||||
set is_conflict_diff 0
|
||||
set current_diff_path $path
|
||||
set current_diff_side $w
|
||||
set current_diff_queue {}
|
||||
ui_status [mc "Loading diff of %s..." [escape_path $path]]
|
||||
|
||||
set cont_info [list $scroll_pos $callback]
|
||||
|
||||
if {[string first {U} $m] >= 0} {
|
||||
merge_load_stages $path [list show_unmerged_diff $scroll_pos]
|
||||
merge_load_stages $path [list show_unmerged_diff $cont_info]
|
||||
} elseif {$m eq {_O}} {
|
||||
show_other_diff $path $w $m $scroll_pos
|
||||
show_other_diff $path $w $m $cont_info
|
||||
} else {
|
||||
start_show_diff $scroll_pos
|
||||
start_show_diff $cont_info
|
||||
}
|
||||
}
|
||||
|
||||
proc show_unmerged_diff {scroll_pos} {
|
||||
proc show_unmerged_diff {cont_info} {
|
||||
global current_diff_path current_diff_side
|
||||
global merge_stages ui_diff
|
||||
global merge_stages ui_diff is_conflict_diff
|
||||
global current_diff_queue
|
||||
|
||||
if {$merge_stages(2) eq {}} {
|
||||
set is_conflict_diff 1
|
||||
lappend current_diff_queue \
|
||||
[list "LOCAL: deleted\nREMOTE:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":3:$current_diff_path"]]
|
||||
} elseif {$merge_stages(3) eq {}} {
|
||||
set is_conflict_diff 1
|
||||
lappend current_diff_queue \
|
||||
[list "REMOTE: deleted\nLOCAL:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":2:$current_diff_path"]]
|
||||
} elseif {[lindex $merge_stages(1) 0] eq {120000}
|
||||
|| [lindex $merge_stages(2) 0] eq {120000}
|
||||
|| [lindex $merge_stages(3) 0] eq {120000}} {
|
||||
set is_conflict_diff 1
|
||||
lappend current_diff_queue \
|
||||
[list "LOCAL:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":2:$current_diff_path"]]
|
||||
@@ -120,14 +135,14 @@ proc show_unmerged_diff {scroll_pos} {
|
||||
[list "REMOTE:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":3:$current_diff_path"]]
|
||||
} else {
|
||||
start_show_diff $scroll_pos
|
||||
start_show_diff $cont_info
|
||||
return
|
||||
}
|
||||
|
||||
advance_diff_queue $scroll_pos
|
||||
advance_diff_queue $cont_info
|
||||
}
|
||||
|
||||
proc advance_diff_queue {scroll_pos} {
|
||||
proc advance_diff_queue {cont_info} {
|
||||
global current_diff_queue ui_diff
|
||||
|
||||
set item [lindex $current_diff_queue 0]
|
||||
@@ -137,10 +152,10 @@ proc advance_diff_queue {scroll_pos} {
|
||||
$ui_diff insert end [lindex $item 0] [lindex $item 1]
|
||||
$ui_diff conf -state disabled
|
||||
|
||||
start_show_diff $scroll_pos [lindex $item 2]
|
||||
start_show_diff $cont_info [lindex $item 2]
|
||||
}
|
||||
|
||||
proc show_other_diff {path w m scroll_pos} {
|
||||
proc show_other_diff {path w m cont_info} {
|
||||
global file_states file_lists
|
||||
global is_3way_diff diff_active repo_config
|
||||
global ui_diff ui_index ui_workdir
|
||||
@@ -165,7 +180,9 @@ proc show_other_diff {path w m scroll_pos} {
|
||||
}
|
||||
file {
|
||||
set fd [open $path r]
|
||||
fconfigure $fd -eofchar {}
|
||||
fconfigure $fd \
|
||||
-eofchar {} \
|
||||
-encoding [get_path_encoding $path]
|
||||
set content [read $fd $max_sz]
|
||||
close $fd
|
||||
set sz [file size $path]
|
||||
@@ -217,16 +234,21 @@ proc show_other_diff {path w m scroll_pos} {
|
||||
$ui_diff conf -state disabled
|
||||
set diff_active 0
|
||||
unlock_index
|
||||
set scroll_pos [lindex $cont_info 0]
|
||||
if {$scroll_pos ne {}} {
|
||||
update
|
||||
$ui_diff yview moveto $scroll_pos
|
||||
}
|
||||
ui_ready
|
||||
set callback [lindex $cont_info 1]
|
||||
if {$callback ne {}} {
|
||||
eval $callback
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
proc start_show_diff {scroll_pos {add_opts {}}} {
|
||||
proc start_show_diff {cont_info {add_opts {}}} {
|
||||
global file_states file_lists
|
||||
global is_3way_diff diff_active repo_config
|
||||
global ui_diff ui_index ui_workdir
|
||||
@@ -279,14 +301,14 @@ proc start_show_diff {scroll_pos {add_opts {}}} {
|
||||
set ::current_diff_inheader 1
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-encoding binary \
|
||||
-translation binary
|
||||
fileevent $fd readable [list read_diff $fd $scroll_pos]
|
||||
-encoding [get_path_encoding $path] \
|
||||
-translation lf
|
||||
fileevent $fd readable [list read_diff $fd $cont_info]
|
||||
}
|
||||
|
||||
proc read_diff {fd scroll_pos} {
|
||||
proc read_diff {fd cont_info} {
|
||||
global ui_diff diff_active
|
||||
global is_3way_diff current_diff_header
|
||||
global is_3way_diff is_conflict_diff current_diff_header
|
||||
global current_diff_queue
|
||||
|
||||
$ui_diff conf -state normal
|
||||
@@ -334,6 +356,7 @@ proc read_diff {fd scroll_pos} {
|
||||
{--} {set tags d_--}
|
||||
{++} {
|
||||
if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} {
|
||||
set is_conflict_diff 1
|
||||
set line [string replace $line 0 1 { }]
|
||||
set tags d$op
|
||||
} else {
|
||||
@@ -353,6 +376,7 @@ proc read_diff {fd scroll_pos} {
|
||||
{-} {set tags d_-}
|
||||
{+} {
|
||||
if {[regexp {^\+([<>]{7} |={7})} $line _g op]} {
|
||||
set is_conflict_diff 1
|
||||
set line [string replace $line 0 0 { }]
|
||||
set tags d$op
|
||||
} else {
|
||||
@@ -377,12 +401,13 @@ proc read_diff {fd scroll_pos} {
|
||||
close $fd
|
||||
|
||||
if {$current_diff_queue ne {}} {
|
||||
advance_diff_queue $scroll_pos
|
||||
advance_diff_queue $cont_info
|
||||
return
|
||||
}
|
||||
|
||||
set diff_active 0
|
||||
unlock_index
|
||||
set scroll_pos [lindex $cont_info 0]
|
||||
if {$scroll_pos ne {}} {
|
||||
update
|
||||
$ui_diff yview moveto $scroll_pos
|
||||
@@ -392,6 +417,10 @@ proc read_diff {fd scroll_pos} {
|
||||
if {[$ui_diff index end] eq {2.0}} {
|
||||
handle_empty_diff
|
||||
}
|
||||
set callback [lindex $cont_info 1]
|
||||
if {$callback ne {}} {
|
||||
eval $callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,8 +461,9 @@ proc apply_hunk {x y} {
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
set enc [get_path_encoding $current_diff_path]
|
||||
set p [eval git_write $apply_cmd]
|
||||
fconfigure $p -translation binary -encoding binary
|
||||
fconfigure $p -translation binary -encoding $enc
|
||||
puts -nonewline $p $current_diff_header
|
||||
puts -nonewline $p [$ui_diff get $s_lno $e_lno]
|
||||
close $p} err]} {
|
||||
@@ -601,8 +631,9 @@ proc apply_line {x y} {
|
||||
set patch "@@ -$hln,$n +$hln,[eval expr $n $sign 1] @@\n$patch"
|
||||
|
||||
if {[catch {
|
||||
set enc [get_path_encoding $current_diff_path]
|
||||
set p [eval git_write $apply_cmd]
|
||||
fconfigure $p -translation binary -encoding binary
|
||||
fconfigure $p -translation binary -encoding $enc
|
||||
puts -nonewline $p $current_diff_header
|
||||
puts -nonewline $p $patch
|
||||
close $p} err]} {
|
||||
|
||||
@@ -206,7 +206,7 @@ set encoding_aliases {
|
||||
{ ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
|
||||
{ GBK CP936 MS936 windows-936 }
|
||||
{ JIS_Encoding csJISEncoding }
|
||||
{ Shift_JIS MS_Kanji csShiftJIS }
|
||||
{ Shift_JIS MS_Kanji csShiftJIS ShiftJIS Shift-JIS }
|
||||
{ Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
|
||||
EUC-JP }
|
||||
{ Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
|
||||
@@ -240,37 +240,227 @@ set encoding_aliases {
|
||||
{ Big5 csBig5 }
|
||||
}
|
||||
|
||||
proc tcl_encoding {enc} {
|
||||
global encoding_aliases
|
||||
set names [encoding names]
|
||||
set lcnames [string tolower $names]
|
||||
set enc [string tolower $enc]
|
||||
set i [lsearch -exact $lcnames $enc]
|
||||
if {$i < 0} {
|
||||
# look for "isonnn" instead of "iso-nnn" or "iso_nnn"
|
||||
if {[regsub {^iso[-_]} $enc iso encx]} {
|
||||
set i [lsearch -exact $lcnames $encx]
|
||||
}
|
||||
}
|
||||
if {$i < 0} {
|
||||
foreach l $encoding_aliases {
|
||||
set ll [string tolower $l]
|
||||
if {[lsearch -exact $ll $enc] < 0} continue
|
||||
# look through the aliases for one that tcl knows about
|
||||
foreach e $ll {
|
||||
set i [lsearch -exact $lcnames $e]
|
||||
if {$i < 0} {
|
||||
if {[regsub {^iso[-_]} $e iso ex]} {
|
||||
set i [lsearch -exact $lcnames $ex]
|
||||
}
|
||||
}
|
||||
if {$i >= 0} break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$i >= 0} {
|
||||
return [lindex $names $i]
|
||||
}
|
||||
return {}
|
||||
set encoding_groups {
|
||||
{"" ""
|
||||
{"Unicode" UTF-8}
|
||||
{"Western" ISO-8859-1}}
|
||||
{we "West European"
|
||||
{"Western" ISO-8859-15 CP-437 CP-850 MacRoman CP-1252 Windows-1252}
|
||||
{"Celtic" ISO-8859-14}
|
||||
{"Greek" ISO-8859-14 ISO-8859-7 CP-737 CP-869 MacGreek CP-1253 Windows-1253}
|
||||
{"Icelandic" MacIceland MacIcelandic CP-861}
|
||||
{"Nordic" ISO-8859-10 CP-865}
|
||||
{"Portuguese" CP-860}
|
||||
{"South European" ISO-8859-3}}
|
||||
{ee "East European"
|
||||
{"Baltic" CP-775 ISO-8859-4 ISO-8859-13 CP-1257 Windows-1257}
|
||||
{"Central European" CP-852 ISO-8859-2 MacCE CP-1250 Windows-1250}
|
||||
{"Croatian" MacCroatian}
|
||||
{"Cyrillic" CP-855 ISO-8859-5 ISO-IR-111 KOI8-R MacCyrillic CP-1251 Windows-1251}
|
||||
{"Russian" CP-866}
|
||||
{"Ukrainian" KOI8-U MacUkraine MacUkrainian}
|
||||
{"Romanian" ISO-8859-16 MacRomania MacRomanian}}
|
||||
{ea "East Asian"
|
||||
{"Generic" ISO-2022}
|
||||
{"Chinese Simplified" GB2312 GB1988 GB12345 GB2312-RAW GBK EUC-CN GB18030 HZ ISO-2022-CN}
|
||||
{"Chinese Traditional" Big5 Big5-HKSCS EUC-TW CP-950}
|
||||
{"Japanese" EUC-JP ISO-2022-JP Shift-JIS JIS-0212 JIS-0208 JIS-0201 CP-932 MacJapan}
|
||||
{"Korean" EUC-KR UHC JOHAB ISO-2022-KR CP-949 KSC5601}}
|
||||
{sa "SE & SW Asian"
|
||||
{"Armenian" ARMSCII-8}
|
||||
{"Georgian" GEOSTD8}
|
||||
{"Thai" TIS-620 ISO-8859-11 CP-874 Windows-874 MacThai}
|
||||
{"Turkish" CP-857 CP857 ISO-8859-9 MacTurkish CP-1254 Windows-1254}
|
||||
{"Vietnamese" TCVN VISCII VPS CP-1258 Windows-1258}
|
||||
{"Hindi" MacDevanagari}
|
||||
{"Gujarati" MacGujarati}
|
||||
{"Gurmukhi" MacGurmukhi}}
|
||||
{me "Middle Eastern"
|
||||
{"Arabic" ISO-8859-6 Windows-1256 CP-1256 CP-864 MacArabic}
|
||||
{"Farsi" MacFarsi}
|
||||
{"Hebrew" ISO-8859-8-I Windows-1255 CP-1255 ISO-8859-8 CP-862 MacHebrew}}
|
||||
{mi "Misc"
|
||||
{"7-bit" ASCII}
|
||||
{"16-bit" Unicode}
|
||||
{"Legacy" CP-863 EBCDIC}
|
||||
{"Symbol" Symbol Dingbats MacDingbats MacCentEuro}}
|
||||
}
|
||||
|
||||
proc build_encoding_table {} {
|
||||
global encoding_aliases encoding_lookup_table
|
||||
|
||||
# Prepare the lookup list; cannot use lsort -nocase because
|
||||
# of compatibility issues with older Tcl (e.g. in msysgit)
|
||||
set names [list]
|
||||
foreach item [encoding names] {
|
||||
lappend names [list [string tolower $item] $item]
|
||||
}
|
||||
set names [lsort -ascii -index 0 $names]
|
||||
# neither can we use lsearch -index
|
||||
set lnames [list]
|
||||
foreach item $names {
|
||||
lappend lnames [lindex $item 0]
|
||||
}
|
||||
|
||||
foreach grp $encoding_aliases {
|
||||
set target {}
|
||||
foreach item $grp {
|
||||
set i [lsearch -sorted -ascii $lnames \
|
||||
[string tolower $item]]
|
||||
if {$i >= 0} {
|
||||
set target [lindex $names $i 1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$target eq {}} continue
|
||||
foreach item $grp {
|
||||
set encoding_lookup_table([string tolower $item]) $target
|
||||
}
|
||||
}
|
||||
|
||||
foreach item $names {
|
||||
set encoding_lookup_table([lindex $item 0]) [lindex $item 1]
|
||||
}
|
||||
}
|
||||
|
||||
proc tcl_encoding {enc} {
|
||||
global encoding_lookup_table
|
||||
if {$enc eq {}} {
|
||||
return {}
|
||||
}
|
||||
if {![info exists encoding_lookup_table]} {
|
||||
build_encoding_table
|
||||
}
|
||||
set enc [string tolower $enc]
|
||||
if {![info exists encoding_lookup_table($enc)]} {
|
||||
# look for "isonnn" instead of "iso-nnn" or "iso_nnn"
|
||||
if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} {
|
||||
set enc $encx
|
||||
}
|
||||
}
|
||||
if {[info exists encoding_lookup_table($enc)]} {
|
||||
return $encoding_lookup_table($enc)
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
proc force_path_encoding {path enc} {
|
||||
global path_encoding_overrides last_encoding_override
|
||||
|
||||
set enc [tcl_encoding $enc]
|
||||
if {$enc eq {}} {
|
||||
catch { unset last_encoding_override }
|
||||
catch { unset path_encoding_overrides($path) }
|
||||
} else {
|
||||
set last_encoding_override $enc
|
||||
if {$path ne {}} {
|
||||
set path_encoding_overrides($path) $enc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc get_path_encoding {path} {
|
||||
global path_encoding_overrides last_encoding_override
|
||||
|
||||
if {[info exists last_encoding_override]} {
|
||||
set tcl_enc $last_encoding_override
|
||||
} else {
|
||||
set tcl_enc [tcl_encoding [get_config gui.encoding]]
|
||||
}
|
||||
if {$tcl_enc eq {}} {
|
||||
set tcl_enc [encoding system]
|
||||
}
|
||||
if {$path ne {}} {
|
||||
if {[info exists path_encoding_overrides($path)]} {
|
||||
set enc2 $path_encoding_overrides($path)
|
||||
} else {
|
||||
set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]]
|
||||
}
|
||||
if {$enc2 ne {}} {
|
||||
set tcl_enc $enc2
|
||||
}
|
||||
}
|
||||
return $tcl_enc
|
||||
}
|
||||
|
||||
proc build_encoding_submenu {parent grp cmd} {
|
||||
global used_encodings
|
||||
|
||||
set mid [lindex $grp 0]
|
||||
set gname [mc [lindex $grp 1]]
|
||||
|
||||
set smenu {}
|
||||
foreach subset [lrange $grp 2 end] {
|
||||
set name [mc [lindex $subset 0]]
|
||||
|
||||
foreach enc [lrange $subset 1 end] {
|
||||
set tcl_enc [tcl_encoding $enc]
|
||||
if {$tcl_enc eq {}} continue
|
||||
|
||||
if {$smenu eq {}} {
|
||||
if {$mid eq {}} {
|
||||
set smenu $parent
|
||||
} else {
|
||||
set smenu "$parent.$mid"
|
||||
menu $smenu
|
||||
$parent add cascade \
|
||||
-label $gname \
|
||||
-menu $smenu
|
||||
}
|
||||
}
|
||||
|
||||
if {$name ne {}} {
|
||||
set lbl "$name ($enc)"
|
||||
} else {
|
||||
set lbl $enc
|
||||
}
|
||||
$smenu add command \
|
||||
-label $lbl \
|
||||
-command [concat $cmd [list $tcl_enc]]
|
||||
|
||||
lappend used_encodings $tcl_enc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc popup_btn_menu {m b} {
|
||||
tk_popup $m [winfo pointerx $b] [winfo pointery $b]
|
||||
}
|
||||
|
||||
proc build_encoding_menu {emenu cmd {nodef 0}} {
|
||||
$emenu configure -postcommand \
|
||||
[list do_build_encoding_menu $emenu $cmd $nodef]
|
||||
}
|
||||
|
||||
proc do_build_encoding_menu {emenu cmd {nodef 0}} {
|
||||
global used_encodings encoding_groups
|
||||
|
||||
$emenu configure -postcommand {}
|
||||
|
||||
if {!$nodef} {
|
||||
$emenu add command \
|
||||
-label [mc "Default"] \
|
||||
-command [concat $cmd [list {}]]
|
||||
}
|
||||
set sysenc [encoding system]
|
||||
$emenu add command \
|
||||
-label [mc "System (%s)" $sysenc] \
|
||||
-command [concat $cmd [list $sysenc]]
|
||||
|
||||
# Main encoding tree
|
||||
set used_encodings [list identity]
|
||||
$emenu add separator
|
||||
foreach grp $encoding_groups {
|
||||
build_encoding_submenu $emenu $grp $cmd
|
||||
}
|
||||
|
||||
# Add unclassified encodings
|
||||
set unused_grp [list [mc Other]]
|
||||
foreach enc [encoding names] {
|
||||
if {[lsearch -exact $used_encodings $enc] < 0} {
|
||||
lappend unused_grp $enc
|
||||
}
|
||||
}
|
||||
build_encoding_submenu $emenu [list other [mc Other] $unused_grp] $cmd
|
||||
}
|
||||
|
||||
@@ -5,24 +5,51 @@ proc merge_resolve_one {stage} {
|
||||
global current_diff_path
|
||||
|
||||
switch -- $stage {
|
||||
1 { set target [mc "the base version"] }
|
||||
2 { set target [mc "this branch"] }
|
||||
3 { set target [mc "the other branch"] }
|
||||
1 { set targetquestion [mc "Force resolution to the base version?"] }
|
||||
2 { set targetquestion [mc "Force resolution to this branch?"] }
|
||||
3 { set targetquestion [mc "Force resolution to the other branch?"] }
|
||||
}
|
||||
|
||||
set op_question [mc "Force resolution to %s?
|
||||
Note that the diff shows only conflicting changes.
|
||||
set op_question [strcat $targetquestion "\n" \
|
||||
[mc "Note that the diff shows only conflicting changes.
|
||||
|
||||
%s will be overwritten.
|
||||
|
||||
This operation can be undone only by restarting the merge." \
|
||||
$target [short_path $current_diff_path]]
|
||||
[short_path $current_diff_path]]]
|
||||
|
||||
if {[ask_popup $op_question] eq {yes}} {
|
||||
merge_load_stages $current_diff_path [list merge_force_stage $stage]
|
||||
}
|
||||
}
|
||||
|
||||
proc merge_stage_workdir {path w lno} {
|
||||
global current_diff_path diff_active
|
||||
|
||||
if {$diff_active} return
|
||||
|
||||
if {$path ne $current_diff_path} {
|
||||
show_diff $path $w $lno {} [list do_merge_stage_workdir $path]
|
||||
} else {
|
||||
do_merge_stage_workdir $path
|
||||
}
|
||||
}
|
||||
|
||||
proc do_merge_stage_workdir {path} {
|
||||
global current_diff_path is_conflict_diff
|
||||
|
||||
if {$path ne $current_diff_path} return;
|
||||
|
||||
if {$is_conflict_diff} {
|
||||
if {[ask_popup [mc "File %s seems to have unresolved conflicts, still stage?" \
|
||||
[short_path $path]]] ne {yes}} {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
merge_add_resolution $path
|
||||
}
|
||||
|
||||
proc merge_add_resolution {path} {
|
||||
global current_diff_path ui_workdir
|
||||
|
||||
|
||||
@@ -1,6 +1,28 @@
|
||||
# git-gui options editor
|
||||
# Copyright (C) 2006, 2007 Shawn Pearce
|
||||
|
||||
proc config_check_encodings {} {
|
||||
global repo_config_new global_config_new
|
||||
|
||||
set enc $global_config_new(gui.encoding)
|
||||
if {$enc eq {}} {
|
||||
set global_config_new(gui.encoding) [encoding system]
|
||||
} elseif {[tcl_encoding $enc] eq {}} {
|
||||
error_popup [mc "Invalid global encoding '%s'" $enc]
|
||||
return 0
|
||||
}
|
||||
|
||||
set enc $repo_config_new(gui.encoding)
|
||||
if {$enc eq {}} {
|
||||
set repo_config_new(gui.encoding) [encoding system]
|
||||
} elseif {[tcl_encoding $enc] eq {}} {
|
||||
error_popup [mc "Invalid repo encoding '%s'" $enc]
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
proc save_config {} {
|
||||
global default_config font_descs
|
||||
global repo_config global_config
|
||||
@@ -130,6 +152,7 @@ proc do_options {} {
|
||||
{i-1..99 gui.diffcontext {mc "Number of Diff Context Lines"}}
|
||||
{i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}}
|
||||
{t gui.newbranchtemplate {mc "New Branch Name Template"}}
|
||||
{c gui.encoding {mc "Default File Contents Encoding"}}
|
||||
} {
|
||||
set type [lindex $option 0]
|
||||
set name [lindex $option 1]
|
||||
@@ -159,6 +182,7 @@ proc do_options {} {
|
||||
pack $w.$f.$optid.v -side right -anchor e -padx 5
|
||||
pack $w.$f.$optid -side top -anchor w -fill x
|
||||
}
|
||||
c -
|
||||
t {
|
||||
frame $w.$f.$optid
|
||||
label $w.$f.$optid.l -text "$text:"
|
||||
@@ -171,6 +195,16 @@ proc do_options {} {
|
||||
pack $w.$f.$optid.v -side left -anchor w \
|
||||
-fill x -expand 1 \
|
||||
-padx 5
|
||||
if {$type eq {c}} {
|
||||
menu $w.$f.$optid.m
|
||||
build_encoding_menu $w.$f.$optid.m \
|
||||
[list set ${f}_config_new($name)] 1
|
||||
button $w.$f.$optid.b \
|
||||
-text [mc "Change"] \
|
||||
-command [list popup_btn_menu \
|
||||
$w.$f.$optid.m $w.$f.$optid.b]
|
||||
pack $w.$f.$optid.b -side left -anchor w
|
||||
}
|
||||
pack $w.$f.$optid -side top -anchor w -fill x
|
||||
}
|
||||
}
|
||||
@@ -275,6 +309,7 @@ proc do_restore_defaults {} {
|
||||
}
|
||||
|
||||
proc do_save_config {w} {
|
||||
if {![config_check_encodings]} return
|
||||
if {[catch {save_config} err]} {
|
||||
error_popup [strcat [mc "Failed to completely save options:"] "\n\n$err"]
|
||||
}
|
||||
|
||||
193
git-gui/po/de.po
193
git-gui/po/de.po
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: git-gui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-08-02 08:58+0200\n"
|
||||
"PO-Revision-Date: 2008-08-02 09:09+0200\n"
|
||||
"POT-Creation-Date: 2008-09-13 10:20+0200\n"
|
||||
"PO-Revision-Date: 2008-09-13 10:24+0200\n"
|
||||
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
|
||||
"Language-Team: German\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -110,7 +110,15 @@ msgstr "Teilweise bereitgestellt zum Eintragen"
|
||||
msgid "Staged for commit, missing"
|
||||
msgstr "Bereitgestellt zum Eintragen, fehlend"
|
||||
|
||||
#: git-gui.sh:1597
|
||||
#: git-gui.sh:1658
|
||||
msgid "File type changed, not staged"
|
||||
msgstr "Dateityp geändert, nicht bereitgestellt"
|
||||
|
||||
#: git-gui.sh:1659
|
||||
msgid "File type changed, staged"
|
||||
msgstr "Dateityp geändert, bereitgestellt"
|
||||
|
||||
#: git-gui.sh:1661
|
||||
msgid "Untracked, not staged"
|
||||
msgstr "Nicht unter Versionskontrolle, nicht bereitgestellt"
|
||||
|
||||
@@ -396,15 +404,7 @@ msgstr "Alle kopieren"
|
||||
msgid "File:"
|
||||
msgstr "Datei:"
|
||||
|
||||
#: git-gui.sh:2589
|
||||
msgid "Apply/Reverse Hunk"
|
||||
msgstr "Kontext anwenden/umkehren"
|
||||
|
||||
#: git-gui.sh:2696
|
||||
msgid "Apply/Reverse Line"
|
||||
msgstr "Zeile anwenden/umkehren"
|
||||
|
||||
#: git-gui.sh:2711
|
||||
#: git-gui.sh:2834
|
||||
msgid "Refresh"
|
||||
msgstr "Aktualisieren"
|
||||
|
||||
@@ -416,7 +416,35 @@ msgstr "Schriftgröße verkleinern"
|
||||
msgid "Increase Font Size"
|
||||
msgstr "Schriftgröße vergrößern"
|
||||
|
||||
#: git-gui.sh:2646
|
||||
#: git-gui.sh:2870
|
||||
msgid "Apply/Reverse Hunk"
|
||||
msgstr "Kontext anwenden/umkehren"
|
||||
|
||||
#: git-gui.sh:2875
|
||||
msgid "Apply/Reverse Line"
|
||||
msgstr "Zeile anwenden/umkehren"
|
||||
|
||||
#: git-gui.sh:2885
|
||||
msgid "Run Merge Tool"
|
||||
msgstr "Zusammenführungswerkzeug"
|
||||
|
||||
#: git-gui.sh:2890
|
||||
msgid "Use Remote Version"
|
||||
msgstr "Entfernte Version benutzen"
|
||||
|
||||
#: git-gui.sh:2894
|
||||
msgid "Use Local Version"
|
||||
msgstr "Lokale Version benutzen"
|
||||
|
||||
#: git-gui.sh:2898
|
||||
msgid "Revert To Base"
|
||||
msgstr "Ursprüngliche Version benutzen"
|
||||
|
||||
#: git-gui.sh:2906
|
||||
msgid "Stage Working Copy"
|
||||
msgstr "Arbeitskopie bereitstellen"
|
||||
|
||||
#: git-gui.sh:2925
|
||||
msgid "Unstage Hunk From Commit"
|
||||
msgstr "Kontext aus Bereitstellung herausnehmen"
|
||||
|
||||
@@ -498,7 +526,15 @@ msgstr "Version kopieren"
|
||||
msgid "Do Full Copy Detection"
|
||||
msgstr "Volle Kopie-Erkennung"
|
||||
|
||||
#: lib/blame.tcl:388
|
||||
#: lib/blame.tcl:263
|
||||
msgid "Show History Context"
|
||||
msgstr "Historien-Kontext anzeigen"
|
||||
|
||||
#: lib/blame.tcl:266
|
||||
msgid "Blame Parent Commit"
|
||||
msgstr "Elternversion annotieren"
|
||||
|
||||
#: lib/blame.tcl:394
|
||||
#, tcl-format
|
||||
msgid "Reading %s..."
|
||||
msgstr "%s lesen..."
|
||||
@@ -547,7 +583,19 @@ msgstr "Eintragender:"
|
||||
msgid "Original File:"
|
||||
msgstr "Ursprüngliche Datei:"
|
||||
|
||||
#: lib/blame.tcl:925
|
||||
#: lib/blame.tcl:990
|
||||
msgid "Cannot find parent commit:"
|
||||
msgstr "Elternversion kann nicht gefunden werden:"
|
||||
|
||||
#: lib/blame.tcl:1001
|
||||
msgid "Unable to display parent"
|
||||
msgstr "Elternversion kann nicht angezeigt werden"
|
||||
|
||||
#: lib/blame.tcl:1002 lib/diff.tcl:191
|
||||
msgid "Error loading diff:"
|
||||
msgstr "Fehler beim Laden des Vergleichs:"
|
||||
|
||||
#: lib/blame.tcl:1142
|
||||
msgid "Originally By:"
|
||||
msgstr "Ursprünglich von:"
|
||||
|
||||
@@ -1494,11 +1542,7 @@ msgstr "Git-Projektarchiv (Unterprojekt)"
|
||||
msgid "* Binary file (not showing content)."
|
||||
msgstr "* Binärdatei (Inhalt wird nicht angezeigt)"
|
||||
|
||||
#: lib/diff.tcl:185
|
||||
msgid "Error loading diff:"
|
||||
msgstr "Fehler beim Laden des Vergleichs:"
|
||||
|
||||
#: lib/diff.tcl:303
|
||||
#: lib/diff.tcl:313
|
||||
msgid "Failed to unstage selected hunk."
|
||||
msgstr ""
|
||||
"Fehler beim Herausnehmen des gewählten Kontexts aus der Bereitstellung."
|
||||
@@ -1586,6 +1630,15 @@ msgstr ""
|
||||
msgid "Do Nothing"
|
||||
msgstr "Nichts tun"
|
||||
|
||||
#: lib/index.tcl:419
|
||||
msgid "Reverting selected files"
|
||||
msgstr "Änderungen in gewählten Dateien verwerfen"
|
||||
|
||||
#: lib/index.tcl:423
|
||||
#, tcl-format
|
||||
msgid "Reverting %s"
|
||||
msgstr "Änderungen in %s verwerfen"
|
||||
|
||||
#: lib/merge.tcl:13
|
||||
msgid ""
|
||||
"Cannot merge while amending.\n"
|
||||
@@ -1730,6 +1783,96 @@ msgstr "Abbruch fehlgeschlagen."
|
||||
msgid "Abort completed. Ready."
|
||||
msgstr "Abbruch durchgeführt. Bereit."
|
||||
|
||||
#: lib/mergetool.tcl:14
|
||||
msgid "Force resolution to the base version?"
|
||||
msgstr "Konflikt durch Basisversion ersetzen?"
|
||||
|
||||
#: lib/mergetool.tcl:15
|
||||
msgid "Force resolution to this branch?"
|
||||
msgstr "Konflikt durch diesen Zweig ersetzen?"
|
||||
|
||||
#: lib/mergetool.tcl:16
|
||||
msgid "Force resolution to the other branch?"
|
||||
msgstr "Konflikt durch anderen Zweig ersetzen?"
|
||||
|
||||
#: lib/mergetool.tcl:20
|
||||
#, tcl-format
|
||||
msgid ""
|
||||
"Note that the diff shows only conflicting changes.\n"
|
||||
"\n"
|
||||
"%s will be overwritten.\n"
|
||||
"\n"
|
||||
"This operation can be undone only by restarting the merge."
|
||||
msgstr ""
|
||||
"Hinweis: Der Vergleich zeigt nur konfliktverursachende Änderungen an.\n"
|
||||
"\n"
|
||||
"»%s« wird überschrieben.\n"
|
||||
"\n"
|
||||
"Diese Operation kann nur rückgängig gemacht werden, wenn die\n"
|
||||
"Zusammenführung erneut gestartet wird."
|
||||
|
||||
#: lib/mergetool.tcl:32
|
||||
#, tcl-format
|
||||
msgid "Adding resolution for %s"
|
||||
msgstr "Auflösung hinzugefügt für %s"
|
||||
|
||||
#: lib/mergetool.tcl:119
|
||||
msgid "Cannot resolve deletion or link conflicts using a tool"
|
||||
msgstr ""
|
||||
"Konflikte durch gelöschte Dateien oder symbolische Links können nicht durch "
|
||||
"das Zusamenführungswerkzeug gelöst werden."
|
||||
|
||||
#: lib/mergetool.tcl:124
|
||||
msgid "Conflict file does not exist"
|
||||
msgstr "Konflikt-Datei existiert nicht"
|
||||
|
||||
#: lib/mergetool.tcl:236
|
||||
#, tcl-format
|
||||
msgid "Not a GUI merge tool: '%s'"
|
||||
msgstr "Kein GUI Zusammenführungswerkzeug: »%s«"
|
||||
|
||||
#: lib/mergetool.tcl:240
|
||||
#, tcl-format
|
||||
msgid "Unsupported merge tool '%s'"
|
||||
msgstr "Unbekanntes Zusammenführungswerkzeug: »%s«"
|
||||
|
||||
#: lib/mergetool.tcl:275
|
||||
msgid "Merge tool is already running, terminate it?"
|
||||
msgstr "Zusammenführungswerkzeug läuft bereits. Soll es abgebrochen werden?"
|
||||
|
||||
#: lib/mergetool.tcl:295
|
||||
#, tcl-format
|
||||
msgid ""
|
||||
"Error retrieving versions:\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
"Fehler beim Abrufen der Dateiversionen:\n"
|
||||
"%s"
|
||||
|
||||
#: lib/mergetool.tcl:315
|
||||
#, tcl-format
|
||||
msgid ""
|
||||
"Could not start the merge tool:\n"
|
||||
"\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
"Zusammenführungswerkzeug konnte nicht gestartet werden:\n"
|
||||
"\n"
|
||||
"%s"
|
||||
|
||||
#: lib/mergetool.tcl:319
|
||||
msgid "Running merge tool..."
|
||||
msgstr "Zusammenführungswerkzeug starten..."
|
||||
|
||||
#: lib/mergetool.tcl:347 lib/mergetool.tcl:363
|
||||
msgid "Merge tool failed."
|
||||
msgstr "Zusammenführungswerkzeug fehlgeschlagen."
|
||||
|
||||
#: lib/mergetool.tcl:353
|
||||
#, tcl-format
|
||||
msgid "File %s unchanged, still accept as resolved?"
|
||||
msgstr "Datei »%s« unverändert. Trotzdem Konflikt als gelöst akzeptieren?"
|
||||
|
||||
#: lib/option.tcl:95
|
||||
msgid "Restore Defaults"
|
||||
msgstr "Voreinstellungen wiederherstellen"
|
||||
@@ -1767,7 +1910,11 @@ msgstr "Ausführlichkeit der Zusammenführen-Meldungen"
|
||||
msgid "Show Diffstat After Merge"
|
||||
msgstr "Vergleichsstatistik nach Zusammenführen anzeigen"
|
||||
|
||||
#: lib/option.tcl:123
|
||||
#: lib/option.tcl:122
|
||||
msgid "Use Merge Tool"
|
||||
msgstr "Zusammenführungswerkzeug"
|
||||
|
||||
#: lib/option.tcl:124
|
||||
msgid "Trust File Modification Timestamps"
|
||||
msgstr "Auf Dateiänderungsdatum verlassen"
|
||||
|
||||
@@ -1788,6 +1935,10 @@ msgid "Minimum Letters To Blame Copy On"
|
||||
msgstr "Mindestzahl Zeichen für Kopie-Annotieren"
|
||||
|
||||
#: lib/option.tcl:128
|
||||
msgid "Blame History Context Radius (days)"
|
||||
msgstr "Anzahl Tage für Historien-Kontext"
|
||||
|
||||
#: lib/option.tcl:129
|
||||
msgid "Number of Diff Context Lines"
|
||||
msgstr "Anzahl der Kontextzeilen beim Vergleich"
|
||||
|
||||
|
||||
@@ -65,6 +65,16 @@ output () {
|
||||
esac
|
||||
}
|
||||
|
||||
run_pre_rebase_hook () {
|
||||
if test -x "$GIT_DIR/hooks/pre-rebase"
|
||||
then
|
||||
"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
|
||||
echo >&2 "The pre-rebase hook refused to rebase."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
require_clean_work_tree () {
|
||||
# test if working tree is dirty
|
||||
git rev-parse --verify HEAD > /dev/null &&
|
||||
@@ -304,23 +314,28 @@ do_next () {
|
||||
|
||||
mark_action_done
|
||||
make_squash_message $sha1 > "$MSG"
|
||||
failed=f
|
||||
author_script=$(get_author_ident_from_commit HEAD)
|
||||
output git reset --soft HEAD^
|
||||
pick_one -n $sha1 || failed=t
|
||||
case "$(peek_next_command)" in
|
||||
squash|s)
|
||||
EDIT_COMMIT=
|
||||
USE_OUTPUT=output
|
||||
MSG_OPT=-F
|
||||
MSG_FILE="$MSG"
|
||||
cp "$MSG" "$SQUASH_MSG"
|
||||
;;
|
||||
*)
|
||||
EDIT_COMMIT=-e
|
||||
USE_OUTPUT=
|
||||
MSG_OPT=
|
||||
MSG_FILE=
|
||||
rm -f "$SQUASH_MSG" || exit
|
||||
cp "$MSG" "$GIT_DIR"/SQUASH_MSG
|
||||
rm -f "$GIT_DIR"/MERGE_MSG || exit
|
||||
;;
|
||||
esac
|
||||
|
||||
failed=f
|
||||
author_script=$(get_author_ident_from_commit HEAD)
|
||||
output git reset --soft HEAD^
|
||||
pick_one -n $sha1 || failed=t
|
||||
echo "$author_script" > "$DOTEST"/author-script
|
||||
if test $failed = f
|
||||
then
|
||||
@@ -329,7 +344,7 @@ do_next () {
|
||||
GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
|
||||
GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
|
||||
GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
|
||||
$USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT || failed=t
|
||||
$USE_OUTPUT git commit --no-verify $MSG_OPT "$MSG_FILE" $EDIT_COMMIT || failed=t
|
||||
fi
|
||||
if test $failed = t
|
||||
then
|
||||
@@ -507,6 +522,7 @@ first and then run 'git rebase --continue' again."
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
run_pre_rebase_hook ${1+"$@"}
|
||||
test $# -eq 1 -o $# -eq 2 || usage
|
||||
test -d "$DOTEST" &&
|
||||
die "Interactive rebase already started"
|
||||
|
||||
@@ -144,6 +144,16 @@ is_interactive () {
|
||||
done && test -n "$1"
|
||||
}
|
||||
|
||||
run_pre_rebase_hook () {
|
||||
if test -x "$GIT_DIR/hooks/pre-rebase"
|
||||
then
|
||||
"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
|
||||
echo >&2 "The pre-rebase hook refused to rebase."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
test -f "$GIT_DIR"/rebase-apply/applying &&
|
||||
die 'It looks like git-am is in progress. Cannot rebase.'
|
||||
|
||||
@@ -320,13 +330,7 @@ onto_name=${newbase-"$upstream_name"}
|
||||
onto=$(git rev-parse --verify "${onto_name}^0") || exit
|
||||
|
||||
# If a hook exists, give it a chance to interrupt
|
||||
if test -x "$GIT_DIR/hooks/pre-rebase"
|
||||
then
|
||||
"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
|
||||
echo >&2 "The pre-rebase hook refused to rebase."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
run_pre_rebase_hook ${1+"$@"}
|
||||
|
||||
# If the branch to rebase is given, that is the branch we will rebase
|
||||
# $branch_name -- branch being rebased, or HEAD (already detached)
|
||||
|
||||
@@ -39,75 +39,40 @@ package main;
|
||||
sub usage {
|
||||
print <<EOT;
|
||||
git send-email [options] <file | directory>...
|
||||
Options:
|
||||
--from Specify the "From:" line of the email to be sent.
|
||||
|
||||
--to Specify the primary "To:" line of the email.
|
||||
Composing:
|
||||
--from <str> * Email From:
|
||||
--to <str> * Email To:
|
||||
--cc <str> * Email Cc:
|
||||
--bcc <str> * Email Bcc:
|
||||
--subject <str> * Email "Subject:"
|
||||
--in-reply-to <str> * Email "In-Reply-To:"
|
||||
--compose * Open an editor for introduction.
|
||||
|
||||
--cc Specify an initial "Cc:" list for the entire series
|
||||
of emails.
|
||||
Sending:
|
||||
--envelope-sender <str> * Email envelope sender.
|
||||
--smtp-server <str:int> * Outgoing SMTP server to use. The port
|
||||
is optional. Default 'localhost'.
|
||||
--smtp-server-port <int> * Outgoing SMTP server port.
|
||||
--smtp-user <str> * Username for SMTP-AUTH.
|
||||
--smtp-pass <str> * Password for SMTP-AUTH; not necessary.
|
||||
--smtp-encryption <str> * tls or ssl; anything else disables.
|
||||
--smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
|
||||
|
||||
--cc-cmd Specify a command to execute per file which adds
|
||||
per file specific cc address entries
|
||||
Automating:
|
||||
--identity <str> * Use the sendemail.<id> options.
|
||||
--cc-cmd <str> * Email Cc: via `<str> \$patch_path`
|
||||
--suppress-cc <str> * author, self, sob, cccmd, all.
|
||||
--[no-]signed-off-by-cc * Send to Cc: and Signed-off-by:
|
||||
addresses. Default on.
|
||||
--[no-]suppress-from * Send to self. Default off.
|
||||
--[no-]chain-reply-to * Chain In-Reply-To: fields. Default on.
|
||||
--[no-]thread * Use In-Reply-To: field. Default on.
|
||||
|
||||
--bcc Specify a list of email addresses that should be Bcc:
|
||||
on all the emails.
|
||||
|
||||
--compose Use \$GIT_EDITOR, core.editor, \$EDITOR, or \$VISUAL to edit
|
||||
an introductory message for the patch series.
|
||||
|
||||
--subject Specify the initial "Subject:" line.
|
||||
Only necessary if --compose is also set. If --compose
|
||||
is not set, this will be prompted for.
|
||||
|
||||
--in-reply-to Specify the first "In-Reply-To:" header line.
|
||||
Only used if --compose is also set. If --compose is not
|
||||
set, this will be prompted for.
|
||||
|
||||
--chain-reply-to If set, the replies will all be to the previous
|
||||
email sent, rather than to the first email sent.
|
||||
Defaults to on.
|
||||
|
||||
--signed-off-cc Automatically add email addresses that appear in
|
||||
Signed-off-by: or Cc: lines to the cc: list. Defaults to on.
|
||||
|
||||
--identity The configuration identity, a subsection to prioritise over
|
||||
the default section.
|
||||
|
||||
--smtp-server If set, specifies the outgoing SMTP server to use.
|
||||
Defaults to localhost. Port number can be specified here with
|
||||
hostname:port format or by using --smtp-server-port option.
|
||||
|
||||
--smtp-server-port Specify a port on the outgoing SMTP server to connect to.
|
||||
|
||||
--smtp-user The username for SMTP-AUTH.
|
||||
|
||||
--smtp-pass The password for SMTP-AUTH.
|
||||
|
||||
--smtp-encryption Specify 'tls' for STARTTLS encryption, or 'ssl' for SSL.
|
||||
Any other value disables the feature.
|
||||
|
||||
--smtp-ssl Synonym for '--smtp-encryption=ssl'. Deprecated.
|
||||
|
||||
--suppress-cc Suppress the specified category of auto-CC. The category
|
||||
can be one of 'author' for the patch author, 'self' to
|
||||
avoid copying yourself, 'sob' for Signed-off-by lines,
|
||||
'cccmd' for the output of the cccmd, or 'all' to suppress
|
||||
all of these.
|
||||
|
||||
--suppress-from Suppress sending emails to yourself. Defaults to off.
|
||||
|
||||
--thread Specify that the "In-Reply-To:" header should be set on all
|
||||
emails. Defaults to on.
|
||||
|
||||
--quiet Make git-send-email less verbose. One line per email
|
||||
should be all that is output.
|
||||
|
||||
--dry-run Do everything except actually send the emails.
|
||||
|
||||
--envelope-sender Specify the envelope sender used to send the emails.
|
||||
|
||||
--no-validate Don't perform any sanity checks on patches.
|
||||
Administering:
|
||||
--quiet * Output one line of info per email.
|
||||
--dry-run * Don't actually send the emails.
|
||||
--[no-]validate * Perform patch sanity checks. Default on.
|
||||
|
||||
EOT
|
||||
exit(1);
|
||||
@@ -186,17 +151,19 @@ if ($@) {
|
||||
my ($quiet, $dry_run) = (0, 0);
|
||||
|
||||
# Variables with corresponding config settings
|
||||
my ($thread, $chain_reply_to, $suppress_from, $signed_off_cc, $cc_cmd);
|
||||
my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
|
||||
my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
|
||||
my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
|
||||
my ($no_validate);
|
||||
my ($validate);
|
||||
my (@suppress_cc);
|
||||
|
||||
my %config_bool_settings = (
|
||||
"thread" => [\$thread, 1],
|
||||
"chainreplyto" => [\$chain_reply_to, 1],
|
||||
"suppressfrom" => [\$suppress_from, undef],
|
||||
"signedoffcc" => [\$signed_off_cc, undef],
|
||||
"signedoffbycc" => [\$signed_off_by_cc, undef],
|
||||
"signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated
|
||||
"validate" => [\$validate, 1],
|
||||
);
|
||||
|
||||
my %config_settings = (
|
||||
@@ -259,11 +226,11 @@ my $rc = GetOptions("sender|from=s" => \$sender,
|
||||
"cc-cmd=s" => \$cc_cmd,
|
||||
"suppress-from!" => \$suppress_from,
|
||||
"suppress-cc=s" => \@suppress_cc,
|
||||
"signed-off-cc|signed-off-by-cc!" => \$signed_off_cc,
|
||||
"signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
|
||||
"dry-run" => \$dry_run,
|
||||
"envelope-sender=s" => \$envelope_sender,
|
||||
"thread!" => \$thread,
|
||||
"no-validate" => \$no_validate,
|
||||
"validate!" => \$validate,
|
||||
);
|
||||
|
||||
unless ($rc) {
|
||||
@@ -335,7 +302,7 @@ if ($suppress_cc{'all'}) {
|
||||
|
||||
# If explicit old-style ones are specified, they trump --suppress-cc.
|
||||
$suppress_cc{'self'} = $suppress_from if defined $suppress_from;
|
||||
$suppress_cc{'sob'} = !$signed_off_cc if defined $signed_off_cc;
|
||||
$suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
|
||||
|
||||
# Debugging, print out the suppressions.
|
||||
if (0) {
|
||||
@@ -416,7 +383,7 @@ for my $f (@ARGV) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$no_validate) {
|
||||
if ($validate) {
|
||||
foreach my $f (@files) {
|
||||
unless (-p $f) {
|
||||
my $error = validate_patch($f);
|
||||
|
||||
11
git-stash.sh
11
git-stash.sh
@@ -144,17 +144,16 @@ show_stash () {
|
||||
then
|
||||
flags=--stat
|
||||
fi
|
||||
s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@")
|
||||
|
||||
w_commit=$(git rev-parse --verify "$s") &&
|
||||
b_commit=$(git rev-parse --verify "$s^") &&
|
||||
w_commit=$(git rev-parse --verify --default $ref_stash "$@") &&
|
||||
b_commit=$(git rev-parse --verify "$w_commit^") &&
|
||||
git diff $flags $b_commit $w_commit
|
||||
}
|
||||
|
||||
apply_stash () {
|
||||
git update-index -q --refresh &&
|
||||
git diff-files --quiet --ignore-submodules ||
|
||||
die 'Cannot restore on top of a dirty state'
|
||||
die 'Cannot apply to a dirty working tree, please stage your changes'
|
||||
|
||||
unstash_index=
|
||||
case "$1" in
|
||||
@@ -169,7 +168,7 @@ apply_stash () {
|
||||
|
||||
# stash records the work tree, and is a merge between the
|
||||
# base commit (first parent) and the index tree (second parent).
|
||||
s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") &&
|
||||
s=$(git rev-parse --verify --default $ref_stash "$@") &&
|
||||
w_tree=$(git rev-parse --verify "$s:") &&
|
||||
b_tree=$(git rev-parse --verify "$s^1:") &&
|
||||
i_tree=$(git rev-parse --verify "$s^2:") ||
|
||||
@@ -229,7 +228,7 @@ drop_stash () {
|
||||
shift
|
||||
fi
|
||||
# Verify supplied argument looks like a stash entry
|
||||
s=$(git rev-parse --revs-only --no-flags "$@") &&
|
||||
s=$(git rev-parse --verify "$@") &&
|
||||
git rev-parse --verify "$s:" > /dev/null 2>&1 &&
|
||||
git rev-parse --verify "$s^1:" > /dev/null 2>&1 &&
|
||||
git rev-parse --verify "$s^2:" > /dev/null 2>&1 ||
|
||||
|
||||
@@ -194,7 +194,7 @@ cmd_add()
|
||||
else
|
||||
|
||||
module_clone "$path" "$realrepo" || exit
|
||||
(unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
|
||||
(unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) ||
|
||||
die "Unable to checkout submodule '$path'"
|
||||
fi
|
||||
|
||||
@@ -340,8 +340,13 @@ cmd_update()
|
||||
|
||||
if test "$subsha1" != "$sha1"
|
||||
then
|
||||
force=
|
||||
if test -z "$subsha1"
|
||||
then
|
||||
force="-f"
|
||||
fi
|
||||
(unset GIT_DIR; cd "$path" && git-fetch &&
|
||||
git-checkout -q "$sha1") ||
|
||||
git-checkout $force -q "$sha1") ||
|
||||
die "Unable to checkout '$sha1' in submodule path '$path'"
|
||||
|
||||
say "Submodule path '$path': checked out '$sha1'"
|
||||
@@ -634,6 +639,14 @@ cmd_sync()
|
||||
do
|
||||
name=$(module_name "$path")
|
||||
url=$(git config -f .gitmodules --get submodule."$name".url)
|
||||
|
||||
# Possibly a url relative to parent
|
||||
case "$url" in
|
||||
./*|../*)
|
||||
url=$(resolve_relative_url "$url") || exit
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -e "$path"/.git
|
||||
then
|
||||
(
|
||||
|
||||
49
git-svn.perl
49
git-svn.perl
@@ -66,7 +66,7 @@ my ($_stdin, $_help, $_edit,
|
||||
$_version, $_fetch_all, $_no_rebase,
|
||||
$_merge, $_strategy, $_dry_run, $_local,
|
||||
$_prefix, $_no_checkout, $_url, $_verbose,
|
||||
$_git_format, $_commit_url);
|
||||
$_git_format, $_commit_url, $_tag);
|
||||
$Git::SVN::_follow_parent = 1;
|
||||
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
|
||||
'config-dir=s' => \$Git::SVN::Ra::config_dir,
|
||||
@@ -131,6 +131,15 @@ my %cmd = (
|
||||
'revision|r=i' => \$_revision,
|
||||
'no-rebase' => \$_no_rebase,
|
||||
%cmt_opts, %fc_opts } ],
|
||||
branch => [ \&cmd_branch,
|
||||
'Create a branch in the SVN repository',
|
||||
{ 'message|m=s' => \$_message,
|
||||
'dry-run|n' => \$_dry_run,
|
||||
'tag|t' => \$_tag } ],
|
||||
tag => [ sub { $_tag = 1; cmd_branch(@_) },
|
||||
'Create a tag in the SVN repository',
|
||||
{ 'message|m=s' => \$_message,
|
||||
'dry-run|n' => \$_dry_run } ],
|
||||
'set-tree' => [ \&cmd_set_tree,
|
||||
"Set an SVN repository to a git tree-ish",
|
||||
{ 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ],
|
||||
@@ -537,6 +546,42 @@ sub cmd_dcommit {
|
||||
unlink $gs->{index};
|
||||
}
|
||||
|
||||
sub cmd_branch {
|
||||
my ($branch_name, $head) = @_;
|
||||
|
||||
unless (defined $branch_name && length $branch_name) {
|
||||
die(($_tag ? "tag" : "branch") . " name required\n");
|
||||
}
|
||||
$head ||= 'HEAD';
|
||||
|
||||
my ($src, $rev, undef, $gs) = working_head_info($head);
|
||||
|
||||
my $remote = Git::SVN::read_all_remotes()->{svn};
|
||||
my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
|
||||
my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
|
||||
my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
|
||||
|
||||
my $ctx = SVN::Client->new(
|
||||
auth => Git::SVN::Ra::_auth_providers(),
|
||||
log_msg => sub {
|
||||
${ $_[0] } = defined $_message
|
||||
? $_message
|
||||
: 'Create ' . ($_tag ? 'tag ' : 'branch ' )
|
||||
. $branch_name;
|
||||
},
|
||||
);
|
||||
|
||||
eval {
|
||||
$ctx->ls($dst, 'HEAD', 0);
|
||||
} and die "branch ${branch_name} already exists\n";
|
||||
|
||||
print "Copying ${src} at r${rev} to ${dst}...\n";
|
||||
$ctx->copy($src, $rev, $dst)
|
||||
unless $_dry_run;
|
||||
|
||||
$gs->fetch_all;
|
||||
}
|
||||
|
||||
sub cmd_find_rev {
|
||||
my $revision_or_hash = shift or die "SVN or git revision required ",
|
||||
"as a command-line argument\n";
|
||||
@@ -2591,7 +2636,7 @@ sub set_tree {
|
||||
my ($self, $tree) = (shift, shift);
|
||||
my $log_entry = ::get_commit_entry($tree);
|
||||
unless ($self->{last_rev}) {
|
||||
fatal("Must have an existing revision to commit");
|
||||
::fatal("Must have an existing revision to commit");
|
||||
}
|
||||
my %ed_opts = ( r => $self->{last_rev},
|
||||
log => $log_entry->{log},
|
||||
|
||||
@@ -31,7 +31,7 @@ valid_custom_tool()
|
||||
|
||||
valid_tool() {
|
||||
case "$1" in
|
||||
firefox | iceweasel | konqueror | w3m | links | lynx | dillo | open)
|
||||
firefox | iceweasel | konqueror | w3m | links | lynx | dillo | open | start)
|
||||
;; # happy
|
||||
*)
|
||||
valid_custom_tool "$1" || return 1
|
||||
@@ -114,6 +114,10 @@ if test -z "$browser" ; then
|
||||
if test -n "$SECURITYSESSIONID"; then
|
||||
browser_candidates="open $browser_candidates"
|
||||
fi
|
||||
# /bin/start indicates MinGW
|
||||
if test -n /bin/start; then
|
||||
browser_candidates="start $browser_candidates"
|
||||
fi
|
||||
|
||||
for i in $browser_candidates; do
|
||||
init_browser_path $i
|
||||
@@ -157,7 +161,7 @@ case "$browser" in
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
w3m|links|lynx|open)
|
||||
w3m|links|lynx|open|start)
|
||||
eval "$browser_path" "$@"
|
||||
;;
|
||||
dillo)
|
||||
|
||||
3
git.c
3
git.c
@@ -162,6 +162,8 @@ static int handle_alias(int *argcp, const char ***argv)
|
||||
alias_string + 1, alias_command);
|
||||
}
|
||||
count = split_cmdline(alias_string, &new_argv);
|
||||
if (count < 0)
|
||||
die("Bad alias.%s string", alias_command);
|
||||
option_count = handle_options(&new_argv, &count, &envchanged);
|
||||
if (envchanged)
|
||||
die("alias '%s' changes environment variables\n"
|
||||
@@ -328,6 +330,7 @@ static void handle_internal_command(int argc, const char **argv)
|
||||
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
||||
{ "push", cmd_push, RUN_SETUP },
|
||||
{ "read-tree", cmd_read_tree, RUN_SETUP },
|
||||
{ "receive-pack", cmd_receive_pack },
|
||||
{ "reflog", cmd_reflog, RUN_SETUP },
|
||||
{ "remote", cmd_remote, RUN_SETUP },
|
||||
{ "repo-config", cmd_config },
|
||||
|
||||
@@ -435,6 +435,10 @@ div.search {
|
||||
right: 12px
|
||||
}
|
||||
|
||||
p.projsearch {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.linenr {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@ our $version = "++GIT_VERSION++";
|
||||
our $my_url = $cgi->url();
|
||||
our $my_uri = $cgi->url(-absolute => 1);
|
||||
|
||||
# if we're called with PATH_INFO, we have to strip that
|
||||
# from the URL to find our real URL
|
||||
if (my $path_info = $ENV{"PATH_INFO"}) {
|
||||
$my_url =~ s,\Q$path_info\E$,,;
|
||||
$my_uri =~ s,\Q$path_info\E$,,;
|
||||
}
|
||||
|
||||
# core git executable to use
|
||||
# this can just be "git" if your webserver has a sensible PATH
|
||||
our $GIT = "++GIT_BINDIR++/git";
|
||||
@@ -275,6 +282,44 @@ our %feature = (
|
||||
'forks' => {
|
||||
'override' => 0,
|
||||
'default' => [0]},
|
||||
|
||||
# Insert custom links to the action bar of all project pages.
|
||||
# This enables you mainly to link to third-party scripts integrating
|
||||
# into gitweb; e.g. git-browser for graphical history representation
|
||||
# or custom web-based repository administration interface.
|
||||
|
||||
# The 'default' value consists of a list of triplets in the form
|
||||
# (label, link, position) where position is the label after which
|
||||
# to inster the link and link is a format string where %n expands
|
||||
# to the project name, %f to the project path within the filesystem,
|
||||
# %h to the current hash (h gitweb parameter) and %b to the current
|
||||
# hash base (hb gitweb parameter).
|
||||
|
||||
# To enable system wide have in $GITWEB_CONFIG e.g.
|
||||
# $feature{'actions'}{'default'} = [('graphiclog',
|
||||
# '/git-browser/by-commit.html?r=%n', 'summary')];
|
||||
# Project specific override is not supported.
|
||||
'actions' => {
|
||||
'override' => 0,
|
||||
'default' => []},
|
||||
|
||||
# Allow gitweb scan project content tags described in ctags/
|
||||
# of project repository, and display the popular Web 2.0-ish
|
||||
# "tag cloud" near the project list. Note that this is something
|
||||
# COMPLETELY different from the normal Git tags.
|
||||
|
||||
# gitweb by itself can show existing tags, but it does not handle
|
||||
# tagging itself; you need an external application for that.
|
||||
# For an example script, check Girocco's cgi/tagproj.cgi.
|
||||
# You may want to install the HTML::TagCloud Perl module to get
|
||||
# a pretty tag cloud instead of just a list of tags.
|
||||
|
||||
# To enable system wide have in $GITWEB_CONFIG
|
||||
# $feature{'ctags'}{'default'} = ['path_to_tag_script'];
|
||||
# Project specific override is not supported.
|
||||
'ctags' => {
|
||||
'override' => 0,
|
||||
'default' => [0]},
|
||||
);
|
||||
|
||||
sub gitweb_check_feature {
|
||||
@@ -775,7 +820,7 @@ sub quot_cec {
|
||||
);
|
||||
my $chr = ( (exists $es{$cntrl})
|
||||
? $es{$cntrl}
|
||||
: sprintf('\%03o', ord($cntrl)) );
|
||||
: sprintf('\%2x', ord($cntrl)) );
|
||||
if ($opts{-nohtml}) {
|
||||
return $chr;
|
||||
} else {
|
||||
@@ -1755,6 +1800,67 @@ sub git_get_project_description {
|
||||
return $descr;
|
||||
}
|
||||
|
||||
sub git_get_project_ctags {
|
||||
my $path = shift;
|
||||
my $ctags = {};
|
||||
|
||||
$git_dir = "$projectroot/$path";
|
||||
foreach (<$git_dir/ctags/*>) {
|
||||
open CT, $_ or next;
|
||||
my $val = <CT>;
|
||||
chomp $val;
|
||||
close CT;
|
||||
my $ctag = $_; $ctag =~ s#.*/##;
|
||||
$ctags->{$ctag} = $val;
|
||||
}
|
||||
$ctags;
|
||||
}
|
||||
|
||||
sub git_populate_project_tagcloud {
|
||||
my $ctags = shift;
|
||||
|
||||
# First, merge different-cased tags; tags vote on casing
|
||||
my %ctags_lc;
|
||||
foreach (keys %$ctags) {
|
||||
$ctags_lc{lc $_}->{count} += $ctags->{$_};
|
||||
if (not $ctags_lc{lc $_}->{topcount}
|
||||
or $ctags_lc{lc $_}->{topcount} < $ctags->{$_}) {
|
||||
$ctags_lc{lc $_}->{topcount} = $ctags->{$_};
|
||||
$ctags_lc{lc $_}->{topname} = $_;
|
||||
}
|
||||
}
|
||||
|
||||
my $cloud;
|
||||
if (eval { require HTML::TagCloud; 1; }) {
|
||||
$cloud = HTML::TagCloud->new;
|
||||
foreach (sort keys %ctags_lc) {
|
||||
# Pad the title with spaces so that the cloud looks
|
||||
# less crammed.
|
||||
my $title = $ctags_lc{$_}->{topname};
|
||||
$title =~ s/ / /g;
|
||||
$title =~ s/^/ /g;
|
||||
$title =~ s/$/ /g;
|
||||
$cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
|
||||
}
|
||||
} else {
|
||||
$cloud = \%ctags_lc;
|
||||
}
|
||||
$cloud;
|
||||
}
|
||||
|
||||
sub git_show_project_tagcloud {
|
||||
my ($cloud, $count) = @_;
|
||||
print STDERR ref($cloud)."..\n";
|
||||
if (ref $cloud eq 'HTML::TagCloud') {
|
||||
return $cloud->html_and_css($count);
|
||||
} else {
|
||||
my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
|
||||
return '<p align="center">' . join (', ', map {
|
||||
"<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
|
||||
} splice(@tags, 0, $count)) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
sub git_get_project_url_list {
|
||||
my $path = shift;
|
||||
|
||||
@@ -1803,9 +1909,7 @@ sub git_get_projects_list {
|
||||
|
||||
my $subdir = substr($File::Find::name, $pfxlen + 1);
|
||||
# we check related file in $projectroot
|
||||
if ($check_forks and $subdir =~ m#/.#) {
|
||||
$File::Find::prune = 1;
|
||||
} elsif (check_export_ok("$projectroot/$filter/$subdir")) {
|
||||
if (check_export_ok("$projectroot/$filter/$subdir")) {
|
||||
push @list, { path => ($filter ? "$filter/" : '') . $subdir };
|
||||
$File::Find::prune = 1;
|
||||
}
|
||||
@@ -2757,13 +2861,26 @@ sub git_print_page_nav {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$arg{'tree'}{'hash'} = $treehead if defined $treehead;
|
||||
$arg{'tree'}{'hash_base'} = $treebase if defined $treebase;
|
||||
|
||||
my @actions = gitweb_check_feature('actions');
|
||||
while (@actions) {
|
||||
my ($label, $link, $pos) = (shift(@actions), shift(@actions), shift(@actions));
|
||||
@navs = map { $_ eq $pos ? ($_, $label) : $_ } @navs;
|
||||
# munch munch
|
||||
$link =~ s#%n#$project#g;
|
||||
$link =~ s#%f#$git_dir#g;
|
||||
$treehead ? $link =~ s#%h#$treehead#g : $link =~ s#%h##g;
|
||||
$treebase ? $link =~ s#%b#$treebase#g : $link =~ s#%b##g;
|
||||
$arg{$label}{'_href'} = $link;
|
||||
}
|
||||
|
||||
print "<div class=\"page_nav\">\n" .
|
||||
(join " | ",
|
||||
map { $_ eq $current ?
|
||||
$_ : $cgi->a({-href => href(%{$arg{$_}})}, "$_")
|
||||
$_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
|
||||
} @navs);
|
||||
print "<br/>\n$extra<br/>\n" .
|
||||
"</div>\n";
|
||||
@@ -3573,6 +3690,7 @@ sub fill_project_list_info {
|
||||
my ($projlist, $check_forks) = @_;
|
||||
my @projects;
|
||||
|
||||
my $show_ctags = gitweb_check_feature('ctags');
|
||||
PROJECT:
|
||||
foreach my $pr (@$projlist) {
|
||||
my (@activity) = git_get_last_activity($pr->{'path'});
|
||||
@@ -3599,25 +3717,20 @@ sub fill_project_list_info {
|
||||
$pr->{'forks'} = 0;
|
||||
}
|
||||
}
|
||||
$show_ctags and $pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
|
||||
push @projects, $pr;
|
||||
}
|
||||
|
||||
return @projects;
|
||||
}
|
||||
|
||||
# print 'sort by' <th> element, either sorting by $key if $name eq $order
|
||||
# (changing $list), or generating 'sort by $name' replay link otherwise
|
||||
# print 'sort by' <th> element, generating 'sort by $name' replay link
|
||||
# if that order is not selected
|
||||
sub print_sort_th {
|
||||
my ($str_sort, $name, $order, $key, $header, $list) = @_;
|
||||
$key ||= $name;
|
||||
my ($name, $order, $header) = @_;
|
||||
$header ||= ucfirst($name);
|
||||
|
||||
if ($order eq $name) {
|
||||
if ($str_sort) {
|
||||
@$list = sort {$a->{$key} cmp $b->{$key}} @$list;
|
||||
} else {
|
||||
@$list = sort {$a->{$key} <=> $b->{$key}} @$list;
|
||||
}
|
||||
print "<th>$header</th>\n";
|
||||
} else {
|
||||
print "<th>" .
|
||||
@@ -3627,15 +3740,8 @@ sub print_sort_th {
|
||||
}
|
||||
}
|
||||
|
||||
sub print_sort_th_str {
|
||||
print_sort_th(1, @_);
|
||||
}
|
||||
|
||||
sub print_sort_th_num {
|
||||
print_sort_th(0, @_);
|
||||
}
|
||||
|
||||
sub git_project_list_body {
|
||||
# actually uses global variable $project
|
||||
my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
|
||||
|
||||
my ($check_forks) = gitweb_check_feature('forks');
|
||||
@@ -3645,26 +3751,60 @@ sub git_project_list_body {
|
||||
$from = 0 unless defined $from;
|
||||
$to = $#projects if (!defined $to || $#projects < $to);
|
||||
|
||||
my %order_info = (
|
||||
project => { key => 'path', type => 'str' },
|
||||
descr => { key => 'descr_long', type => 'str' },
|
||||
owner => { key => 'owner', type => 'str' },
|
||||
age => { key => 'age', type => 'num' }
|
||||
);
|
||||
my $oi = $order_info{$order};
|
||||
if ($oi->{'type'} eq 'str') {
|
||||
@projects = sort {$a->{$oi->{'key'}} cmp $b->{$oi->{'key'}}} @projects;
|
||||
} else {
|
||||
@projects = sort {$a->{$oi->{'key'}} <=> $b->{$oi->{'key'}}} @projects;
|
||||
}
|
||||
|
||||
my $show_ctags = gitweb_check_feature('ctags');
|
||||
if ($show_ctags) {
|
||||
my %ctags;
|
||||
foreach my $p (@projects) {
|
||||
foreach my $ct (keys %{$p->{'ctags'}}) {
|
||||
$ctags{$ct} += $p->{'ctags'}->{$ct};
|
||||
}
|
||||
}
|
||||
my $cloud = git_populate_project_tagcloud(\%ctags);
|
||||
print git_show_project_tagcloud($cloud, 64);
|
||||
}
|
||||
|
||||
print "<table class=\"project_list\">\n";
|
||||
unless ($no_header) {
|
||||
print "<tr>\n";
|
||||
if ($check_forks) {
|
||||
print "<th></th>\n";
|
||||
}
|
||||
print_sort_th_str('project', $order, 'path',
|
||||
'Project', \@projects);
|
||||
print_sort_th_str('descr', $order, 'descr_long',
|
||||
'Description', \@projects);
|
||||
print_sort_th_str('owner', $order, 'owner',
|
||||
'Owner', \@projects);
|
||||
print_sort_th_num('age', $order, 'age',
|
||||
'Last Change', \@projects);
|
||||
print_sort_th('project', $order, 'Project');
|
||||
print_sort_th('descr', $order, 'Description');
|
||||
print_sort_th('owner', $order, 'Owner');
|
||||
print_sort_th('age', $order, 'Last Change');
|
||||
print "<th></th>\n" . # for links
|
||||
"</tr>\n";
|
||||
}
|
||||
my $alternate = 1;
|
||||
my $tagfilter = $cgi->param('by_tag');
|
||||
for (my $i = $from; $i <= $to; $i++) {
|
||||
my $pr = $projects[$i];
|
||||
|
||||
next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
|
||||
next if $searchtext and not $pr->{'path'} =~ /$searchtext/
|
||||
and not $pr->{'descr_long'} =~ /$searchtext/;
|
||||
# Weed out forks or non-matching entries of search
|
||||
if ($check_forks) {
|
||||
my $forkbase = $project; $forkbase ||= ''; $forkbase =~ s#\.git$#/#;
|
||||
$forkbase="^$forkbase" if $forkbase;
|
||||
next if not $searchtext and not $tagfilter and $show_ctags
|
||||
and $pr->{'path'} =~ m#$forkbase.*/.*#; # regexp-safe
|
||||
}
|
||||
|
||||
if ($alternate) {
|
||||
print "<tr class=\"dark\">\n";
|
||||
} else {
|
||||
@@ -3999,6 +4139,11 @@ sub git_project_list {
|
||||
close $fd;
|
||||
print "</div>\n";
|
||||
}
|
||||
print $cgi->startform(-method => "get") .
|
||||
"<p class=\"projsearch\">Search:\n" .
|
||||
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
|
||||
"</p>" .
|
||||
$cgi->end_form() . "\n";
|
||||
git_project_list_body(\@list, $order);
|
||||
git_footer_html();
|
||||
}
|
||||
@@ -4070,10 +4215,10 @@ sub git_summary {
|
||||
|
||||
print "<div class=\"title\"> </div>\n";
|
||||
print "<table class=\"projects_list\">\n" .
|
||||
"<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
|
||||
"<tr><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
|
||||
"<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
|
||||
"<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
|
||||
if (defined $cd{'rfc2822'}) {
|
||||
print "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
|
||||
print "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
|
||||
}
|
||||
|
||||
# use per project git URL list in $projectroot/$project/cloneurl
|
||||
@@ -4083,9 +4228,23 @@ sub git_summary {
|
||||
@url_list = map { "$_/$project" } @git_base_url_list unless @url_list;
|
||||
foreach my $git_url (@url_list) {
|
||||
next unless $git_url;
|
||||
print "<tr><td>$url_tag</td><td>$git_url</td></tr>\n";
|
||||
print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
|
||||
$url_tag = "";
|
||||
}
|
||||
|
||||
# Tag cloud
|
||||
my $show_ctags = (gitweb_check_feature('ctags'))[0];
|
||||
if ($show_ctags) {
|
||||
my $ctags = git_get_project_ctags($project);
|
||||
my $cloud = git_populate_project_tagcloud($ctags);
|
||||
print "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
|
||||
print "</td>\n<td>" unless %$ctags;
|
||||
print "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
|
||||
print "</td>\n<td>" if %$ctags;
|
||||
print git_show_project_tagcloud($cloud, 48);
|
||||
print "</td></tr>";
|
||||
}
|
||||
|
||||
print "</table>\n";
|
||||
|
||||
if (-s "$projectroot/$project/README.html") {
|
||||
@@ -4124,10 +4283,10 @@ sub git_summary {
|
||||
|
||||
if (@forklist) {
|
||||
git_print_header_div('forks');
|
||||
git_project_list_body(\@forklist, undef, 0, 15,
|
||||
git_project_list_body(\@forklist, 'age', 0, 15,
|
||||
$#forklist <= 15 ? undef :
|
||||
$cgi->a({-href => href(action=>"forks")}, "..."),
|
||||
'noheader');
|
||||
'no_header');
|
||||
}
|
||||
|
||||
git_footer_html();
|
||||
@@ -4445,6 +4604,7 @@ sub git_tree {
|
||||
$hash = $hash_base;
|
||||
}
|
||||
}
|
||||
die_error(404, "No such tree") unless defined($hash);
|
||||
$/ = "\0";
|
||||
open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
|
||||
or die_error(500, "Open git-ls-tree failed");
|
||||
@@ -4485,8 +4645,8 @@ sub git_tree {
|
||||
if ($basedir ne '' && substr($basedir, -1) ne '/') {
|
||||
$basedir .= '/';
|
||||
}
|
||||
git_print_page_path($file_name, 'tree', $hash_base);
|
||||
}
|
||||
git_print_page_path($file_name, 'tree', $hash_base);
|
||||
print "<div class=\"page_body\">\n";
|
||||
print "<table class=\"tree\">\n";
|
||||
my $alternate = 1;
|
||||
@@ -5498,7 +5658,11 @@ sub git_shortlog {
|
||||
}
|
||||
my $refs = git_get_references();
|
||||
|
||||
my @commitlist = parse_commits($hash, 101, (100 * $page));
|
||||
my $commit_hash = $hash;
|
||||
if (defined $hash_parent) {
|
||||
$commit_hash = "$hash_parent..$hash";
|
||||
}
|
||||
my @commitlist = parse_commits($commit_hash, 101, (100 * $page));
|
||||
|
||||
my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $#commitlist >= 100);
|
||||
my $next_link = '';
|
||||
|
||||
57
graph.c
57
graph.c
@@ -4,6 +4,43 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
|
||||
/* Internal API */
|
||||
|
||||
/*
|
||||
* Output the next line for a graph.
|
||||
* This formats the next graph line into the specified strbuf. It is not
|
||||
* terminated with a newline.
|
||||
*
|
||||
* Returns 1 if the line includes the current commit, and 0 otherwise.
|
||||
* graph_next_line() will return 1 exactly once for each time
|
||||
* graph_update() is called.
|
||||
*/
|
||||
static int graph_next_line(struct git_graph *graph, struct strbuf *sb);
|
||||
|
||||
/*
|
||||
* Output a padding line in the graph.
|
||||
* This is similar to graph_next_line(). However, it is guaranteed to
|
||||
* never print the current commit line. Instead, if the commit line is
|
||||
* next, it will simply output a line of vertical padding, extending the
|
||||
* branch lines downwards, but leaving them otherwise unchanged.
|
||||
*/
|
||||
static void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
|
||||
|
||||
/*
|
||||
* Print a strbuf to stdout. If the graph is non-NULL, all lines but the
|
||||
* first will be prefixed with the graph output.
|
||||
*
|
||||
* If the strbuf ends with a newline, the output will end after this
|
||||
* newline. A new graph line will not be printed after the final newline.
|
||||
* If the strbuf is empty, no output will be printed.
|
||||
*
|
||||
* Since the first line will not include the graph ouput, the caller is
|
||||
* responsible for printing this line's graph (perhaps via
|
||||
* graph_show_commit() or graph_show_oneline()) before calling
|
||||
* graph_show_strbuf().
|
||||
*/
|
||||
static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Add colors to the graph.
|
||||
@@ -180,14 +217,6 @@ struct git_graph *graph_init(struct rev_info *opt)
|
||||
return graph;
|
||||
}
|
||||
|
||||
void graph_release(struct git_graph *graph)
|
||||
{
|
||||
free(graph->columns);
|
||||
free(graph->new_columns);
|
||||
free(graph->mapping);
|
||||
free(graph);
|
||||
}
|
||||
|
||||
static void graph_update_state(struct git_graph *graph, enum graph_state s)
|
||||
{
|
||||
graph->prev_state = graph->state;
|
||||
@@ -685,7 +714,7 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
|
||||
strbuf_addch(sb, '*');
|
||||
}
|
||||
|
||||
void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
int seen_this = 0;
|
||||
int i, j;
|
||||
@@ -760,7 +789,7 @@ void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
graph_update_state(graph, GRAPH_COLLAPSING);
|
||||
}
|
||||
|
||||
void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
|
||||
static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
int seen_this = 0;
|
||||
int i, j;
|
||||
@@ -801,7 +830,7 @@ void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
|
||||
graph_update_state(graph, GRAPH_COLLAPSING);
|
||||
}
|
||||
|
||||
void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
|
||||
static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
int i;
|
||||
int *tmp_mapping;
|
||||
@@ -906,7 +935,7 @@ void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
|
||||
graph_update_state(graph, GRAPH_PADDING);
|
||||
}
|
||||
|
||||
int graph_next_line(struct git_graph *graph, struct strbuf *sb)
|
||||
static int graph_next_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
switch (graph->state) {
|
||||
case GRAPH_PADDING:
|
||||
@@ -933,7 +962,7 @@ int graph_next_line(struct git_graph *graph, struct strbuf *sb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
|
||||
static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
@@ -1055,7 +1084,7 @@ int graph_show_remainder(struct git_graph *graph)
|
||||
}
|
||||
|
||||
|
||||
void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
|
||||
static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
|
||||
{
|
||||
char *p;
|
||||
|
||||
|
||||
40
graph.h
40
graph.h
@@ -10,11 +10,6 @@ struct git_graph;
|
||||
*/
|
||||
struct git_graph *graph_init(struct rev_info *opt);
|
||||
|
||||
/*
|
||||
* Destroy a struct git_graph and free associated memory.
|
||||
*/
|
||||
void graph_release(struct git_graph *graph);
|
||||
|
||||
/*
|
||||
* Update a git_graph with a new commit.
|
||||
* This will cause the graph to begin outputting lines for the new commit
|
||||
@@ -26,26 +21,6 @@ void graph_release(struct git_graph *graph);
|
||||
*/
|
||||
void graph_update(struct git_graph *graph, struct commit *commit);
|
||||
|
||||
/*
|
||||
* Output the next line for a graph.
|
||||
* This formats the next graph line into the specified strbuf. It is not
|
||||
* terminated with a newline.
|
||||
*
|
||||
* Returns 1 if the line includes the current commit, and 0 otherwise.
|
||||
* graph_next_line() will return 1 exactly once for each time
|
||||
* graph_update() is called.
|
||||
*/
|
||||
int graph_next_line(struct git_graph *graph, struct strbuf *sb);
|
||||
|
||||
/*
|
||||
* Output a padding line in the graph.
|
||||
* This is similar to graph_next_line(). However, it is guaranteed to
|
||||
* never print the current commit line. Instead, if the commit line is
|
||||
* next, it will simply output a line of vertical padding, extending the
|
||||
* branch lines downwards, but leaving them otherwise unchanged.
|
||||
*/
|
||||
void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
|
||||
|
||||
/*
|
||||
* Determine if a graph has finished outputting lines for the current
|
||||
* commit.
|
||||
@@ -89,21 +64,6 @@ void graph_show_padding(struct git_graph *graph);
|
||||
*/
|
||||
int graph_show_remainder(struct git_graph *graph);
|
||||
|
||||
/*
|
||||
* Print a strbuf to stdout. If the graph is non-NULL, all lines but the
|
||||
* first will be prefixed with the graph output.
|
||||
*
|
||||
* If the strbuf ends with a newline, the output will end after this
|
||||
* newline. A new graph line will not be printed after the final newline.
|
||||
* If the strbuf is empty, no output will be printed.
|
||||
*
|
||||
* Since the first line will not include the graph ouput, the caller is
|
||||
* responsible for printing this line's graph (perhaps via
|
||||
* graph_show_commit() or graph_show_oneline()) before calling
|
||||
* graph_show_strbuf().
|
||||
*/
|
||||
void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
|
||||
|
||||
/*
|
||||
* Print a commit message strbuf and the remainder of the graph to stdout.
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user