Merge branch 'master' into db/fetch-pack
There's a number of tricky conflicts between master and this topic right now due to the rewrite of builtin-push. Junio must have handled these via rerere; I'd rather not deal with them again so I'm pre-merging master into the topic. Besides this topic somehow started to depend on the strbuf series that was in next, but is now in master. It no longer compiles on its own without the strbuf API. * master: (184 commits) Whip post 1.5.3.4 maintenance series into shape. Minor usage update in setgitperms.perl manual: use 'URL' instead of 'url'. manual: add some markup. manual: Fix example finding commits referencing given content. Fix wording in push definition. Fix some typos, punctuation, missing words, minor markup. manual: Fix or remove em dashes. Add a --dry-run option to git-push. Add a --dry-run option to git-send-pack. Fix in-place editing functions in convert.c instaweb: support for Ruby's WEBrick server instaweb: allow for use of auto-generated scripts Add 'git-p4 commit' as an alias for 'git-p4 submit' hg-to-git speedup through selectable repack intervals git-svn: respect Subversion's [auth] section configuration values gtksourceview2 support for gitview fix contrib/hooks/post-receive-email hooks.recipients error message Support cvs via git-shell rebase -i: use diff plumbing instead of porcelain ... Conflicts: Makefile builtin-push.c rsh.c
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@ -25,7 +25,6 @@ git-clone
|
|||||||
git-commit
|
git-commit
|
||||||
git-commit-tree
|
git-commit-tree
|
||||||
git-config
|
git-config
|
||||||
git-convert-objects
|
|
||||||
git-count-objects
|
git-count-objects
|
||||||
git-cvsexportcommit
|
git-cvsexportcommit
|
||||||
git-cvsimport
|
git-cvsimport
|
||||||
@ -172,3 +171,6 @@ config.status
|
|||||||
config.mak.autogen
|
config.mak.autogen
|
||||||
config.mak.append
|
config.mak.append
|
||||||
configure
|
configure
|
||||||
|
tags
|
||||||
|
TAGS
|
||||||
|
cscope*
|
||||||
|
31
Documentation/RelNotes-1.5.3.3.txt
Normal file
31
Documentation/RelNotes-1.5.3.3.txt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
GIT v1.5.3.3 Release Notes
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Fixes since v1.5.3.2
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* git-quiltimport did not like it when a patch described in the
|
||||||
|
series file does not exist.
|
||||||
|
|
||||||
|
* p4 importer missed executable bit in some cases.
|
||||||
|
|
||||||
|
* The default shell on some FreeBSD did not execute the
|
||||||
|
argument parsing code correctly and made git unusable.
|
||||||
|
|
||||||
|
* git-svn incorrectly spawned pager even when the user user
|
||||||
|
explicitly asked not to.
|
||||||
|
|
||||||
|
* sample post-receive hook overquoted the envelope sender
|
||||||
|
value.
|
||||||
|
|
||||||
|
* git-am got confused when the patch contained a change that is
|
||||||
|
only about type and not contents.
|
||||||
|
|
||||||
|
* git-mergetool did not show our and their version of the
|
||||||
|
conflicted file when started from a subdirectory of the
|
||||||
|
project.
|
||||||
|
|
||||||
|
* git-mergetool did not pass correct options when invoking diff3.
|
||||||
|
|
||||||
|
* git-log sometimes invoked underlying "diff" machinery
|
||||||
|
unnecessarily.
|
35
Documentation/RelNotes-1.5.3.4.txt
Normal file
35
Documentation/RelNotes-1.5.3.4.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
GIT v1.5.3.4 Release Notes
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Fixes since v1.5.3.3
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* Change to "git-ls-files" in v1.5.3.3 that was introduced to support
|
||||||
|
partial commit of removal better had a segfaulting bug, which was
|
||||||
|
diagnosed and fixed by Keith and Carl.
|
||||||
|
|
||||||
|
* Performance improvements for rename detection has been backported
|
||||||
|
from the 'master' branch.
|
||||||
|
|
||||||
|
* "git-for-each-ref --format='%(numparent)'" was not working
|
||||||
|
correctly at all, and --format='%(parent)' was not working for
|
||||||
|
merge commits.
|
||||||
|
|
||||||
|
* Sample "post-receive-hook" incorrectly sent out push
|
||||||
|
notification e-mails marked as "From: " the committer of the
|
||||||
|
commit that happened to be at the tip of the branch that was
|
||||||
|
pushed, not from the person who pushed.
|
||||||
|
|
||||||
|
* "git-remote" did not exit non-zero status upon error.
|
||||||
|
|
||||||
|
* "git-add -i" did not respond very well to EOF from tty nor
|
||||||
|
bogus input.
|
||||||
|
|
||||||
|
* "git-rebase -i" squash subcommand incorrectly made the
|
||||||
|
author of later commit the author of resulting commit,
|
||||||
|
instead of taking from the first one in the squashed series.
|
||||||
|
|
||||||
|
* "git-stash apply --index" was not documented.
|
||||||
|
|
||||||
|
* autoconfiguration learned that "ar" command is found as "gas" on
|
||||||
|
some systems.
|
25
Documentation/RelNotes-1.5.3.5.txt
Normal file
25
Documentation/RelNotes-1.5.3.5.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
GIT v1.5.3.5 Release Notes
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Fixes since v1.5.3.4
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* "git-config" silently ignored options after --list; now it wilh
|
||||||
|
error out with a usage message.
|
||||||
|
|
||||||
|
* "git-config --file" failed if the argument used a relative path
|
||||||
|
as it changed directories before opening the file.
|
||||||
|
|
||||||
|
* "git-add -i" did not handle single line hunks correctly.
|
||||||
|
|
||||||
|
* "git-log --follow" did not work unless diff generation (e.g. -p)
|
||||||
|
was also requested.
|
||||||
|
|
||||||
|
* "git-log" printed extra newlines between commits when a diff
|
||||||
|
was generated internally (e.g. -S or --follow) but not displayed.
|
||||||
|
|
||||||
|
* Documention updates for supported (but previously undocumented)
|
||||||
|
options of "git-archive" and "git-reflog".
|
||||||
|
|
||||||
|
* "make clean" no longer deletes the configure script that ships
|
||||||
|
with the git tarball, making multiple architecture builds easier.
|
@ -4,7 +4,22 @@ GIT v1.5.4 Release Notes
|
|||||||
Updates since v1.5.3
|
Updates since v1.5.3
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
* git-reset is now built-in.
|
||||||
|
|
||||||
|
* git-send-email can optionally talk over ssmtp and use SMTP-AUTH.
|
||||||
|
|
||||||
|
* git-rebase learned --whitespace option.
|
||||||
|
|
||||||
|
* git-remote knows --mirror mode.
|
||||||
|
|
||||||
|
* git-merge can call the "post-merge" hook.
|
||||||
|
|
||||||
|
* git-pack-objects can optionally run deltification with multiple threads.
|
||||||
|
|
||||||
|
* git-archive can optionally substitute keywords in files marked with
|
||||||
|
export-subst attribute.
|
||||||
|
|
||||||
|
* Various Perforce importer updates.
|
||||||
|
|
||||||
Fixes since v1.5.3
|
Fixes since v1.5.3
|
||||||
------------------
|
------------------
|
||||||
@ -12,3 +27,9 @@ Fixes since v1.5.3
|
|||||||
All of the fixes in v1.5.3 maintenance series are included in
|
All of the fixes in v1.5.3 maintenance series are included in
|
||||||
this release, unless otherwise noted.
|
this release, unless otherwise noted.
|
||||||
|
|
||||||
|
--
|
||||||
|
exec >/var/tmp/1
|
||||||
|
O=v1.5.3.2-99-ge4b2890
|
||||||
|
echo O=`git describe refs/heads/master`
|
||||||
|
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||||
|
|
||||||
|
@ -94,7 +94,6 @@ git-clone mainporcelain
|
|||||||
git-commit mainporcelain
|
git-commit mainporcelain
|
||||||
git-commit-tree plumbingmanipulators
|
git-commit-tree plumbingmanipulators
|
||||||
git-config ancillarymanipulators
|
git-config ancillarymanipulators
|
||||||
git-convert-objects ancillarymanipulators
|
|
||||||
git-count-objects ancillaryinterrogators
|
git-count-objects ancillaryinterrogators
|
||||||
git-cvsexportcommit foreignscminterface
|
git-cvsexportcommit foreignscminterface
|
||||||
git-cvsimport foreignscminterface
|
git-cvsimport foreignscminterface
|
||||||
|
@ -188,7 +188,7 @@ core.worktree::
|
|||||||
Set the path to the working tree. The value will not be
|
Set the path to the working tree. The value will not be
|
||||||
used in combination with repositories found automatically in
|
used in combination with repositories found automatically in
|
||||||
a .git directory (i.e. $GIT_DIR is not set).
|
a .git directory (i.e. $GIT_DIR is not set).
|
||||||
This can be overriden by the GIT_WORK_TREE environment
|
This can be overridden by the GIT_WORK_TREE environment
|
||||||
variable and the '--work-tree' command line option.
|
variable and the '--work-tree' command line option.
|
||||||
|
|
||||||
core.logAllRefUpdates::
|
core.logAllRefUpdates::
|
||||||
@ -338,6 +338,12 @@ branch.<name>.merge::
|
|||||||
branch.<name>.merge to the desired branch, and use the special setting
|
branch.<name>.merge to the desired branch, and use the special setting
|
||||||
`.` (a period) for branch.<name>.remote.
|
`.` (a period) for branch.<name>.remote.
|
||||||
|
|
||||||
|
branch.<name>.mergeoptions::
|
||||||
|
Sets default options for merging into branch <name>. The syntax and
|
||||||
|
supported options are equal to that of gitlink:git-merge[1], but
|
||||||
|
option values containing whitespace characters are currently not
|
||||||
|
supported.
|
||||||
|
|
||||||
clean.requireForce::
|
clean.requireForce::
|
||||||
A boolean to make git-clean do nothing unless given -f or -n. Defaults
|
A boolean to make git-clean do nothing unless given -f or -n. Defaults
|
||||||
to false.
|
to false.
|
||||||
@ -440,6 +446,19 @@ gc.aggressiveWindow::
|
|||||||
algorithm used by 'git gc --aggressive'. This defaults
|
algorithm used by 'git gc --aggressive'. This defaults
|
||||||
to 10.
|
to 10.
|
||||||
|
|
||||||
|
gc.auto::
|
||||||
|
When there are approximately more than this many loose
|
||||||
|
objects in the repository, `git gc --auto` will pack them.
|
||||||
|
Some Porcelain commands use this command to perform a
|
||||||
|
light-weight garbage collection from time to time. Setting
|
||||||
|
this to 0 disables it.
|
||||||
|
|
||||||
|
gc.autopacklimit::
|
||||||
|
When there are more than this many packs that are not
|
||||||
|
marked with `*.keep` file in the repository, `git gc
|
||||||
|
--auto` consolidates them into one larger pack. Setting
|
||||||
|
this to 0 disables this.
|
||||||
|
|
||||||
gc.packrefs::
|
gc.packrefs::
|
||||||
`git gc` does not run `git pack-refs` in a bare repository by
|
`git gc` does not run `git pack-refs` in a bare repository by
|
||||||
default so that older dumb-transport clients can still fetch
|
default so that older dumb-transport clients can still fetch
|
||||||
@ -580,7 +599,7 @@ merge.summary::
|
|||||||
|
|
||||||
merge.tool::
|
merge.tool::
|
||||||
Controls which merge resolution program is used by
|
Controls which merge resolution program is used by
|
||||||
gitlink:git-mergetool[l]. Valid values are: "kdiff3", "tkdiff",
|
gitlink:git-mergetool[1]. Valid values are: "kdiff3", "tkdiff",
|
||||||
"meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and "opendiff".
|
"meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and "opendiff".
|
||||||
|
|
||||||
merge.verbosity::
|
merge.verbosity::
|
||||||
@ -589,7 +608,7 @@ merge.verbosity::
|
|||||||
message if conflicts were detected. Level 1 outputs only
|
message if conflicts were detected. Level 1 outputs only
|
||||||
conflicts, 2 outputs conflicts and file changes. Level 5 and
|
conflicts, 2 outputs conflicts and file changes. Level 5 and
|
||||||
above outputs debugging information. The default is level 2.
|
above outputs debugging information. The default is level 2.
|
||||||
Can be overriden by 'GIT_MERGE_VERBOSITY' environment variable.
|
Can be overridden by 'GIT_MERGE_VERBOSITY' environment variable.
|
||||||
|
|
||||||
merge.<driver>.name::
|
merge.<driver>.name::
|
||||||
Defines a human readable name for a custom low-level
|
Defines a human readable name for a custom low-level
|
||||||
|
@ -1459,7 +1459,8 @@ Although git is a truly distributed system, it is often
|
|||||||
convenient to organize your project with an informal hierarchy
|
convenient to organize your project with an informal hierarchy
|
||||||
of developers. Linux kernel development is run this way. There
|
of developers. Linux kernel development is run this way. There
|
||||||
is a nice illustration (page 17, "Merges to Mainline") in
|
is a nice illustration (page 17, "Merges to Mainline") in
|
||||||
link:http://tinyurl.com/a2jdg[Randy Dunlap's presentation].
|
link:http://www.xenotime.net/linux/mentor/linux-mentoring-2006.pdf
|
||||||
|
[Randy Dunlap's presentation].
|
||||||
|
|
||||||
It should be stressed that this hierarchy is purely *informal*.
|
It should be stressed that this hierarchy is purely *informal*.
|
||||||
There is nothing fundamental in git that enforces the "chain of
|
There is nothing fundamental in git that enforces the "chain of
|
||||||
|
@ -179,8 +179,8 @@
|
|||||||
|
|
||||||
--ext-diff::
|
--ext-diff::
|
||||||
Allow an external diff helper to be executed. If you set an
|
Allow an external diff helper to be executed. If you set an
|
||||||
external diff driver with gitlink:gitattributes(5), you need
|
external diff driver with gitlink:gitattributes[5], you need
|
||||||
to use this option with gitlink:git-log(1) and friends.
|
to use this option with gitlink:git-log[1] and friends.
|
||||||
|
|
||||||
--no-ext-diff::
|
--no-ext-diff::
|
||||||
Disallow external diff drivers.
|
Disallow external diff drivers.
|
||||||
|
@ -10,7 +10,7 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index]
|
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index]
|
||||||
[--apply] [--no-add] [--index-info] [-R | --reverse]
|
[--apply] [--no-add] [--build-fake-ancestor <file>] [-R | --reverse]
|
||||||
[--allow-binary-replacement | --binary] [--reject] [-z]
|
[--allow-binary-replacement | --binary] [--reject] [-z]
|
||||||
[-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
|
[-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
|
||||||
[--whitespace=<nowarn|warn|error|error-all|strip>]
|
[--whitespace=<nowarn|warn|error|error-all|strip>]
|
||||||
@ -63,12 +63,15 @@ OPTIONS
|
|||||||
cached data, apply the patch, and store the result in the index,
|
cached data, apply the patch, and store the result in the index,
|
||||||
without using the working tree. This implies '--index'.
|
without using the working tree. This implies '--index'.
|
||||||
|
|
||||||
--index-info::
|
--build-fake-ancestor <file>::
|
||||||
Newer git-diff output has embedded 'index information'
|
Newer git-diff output has embedded 'index information'
|
||||||
for each blob to help identify the original version that
|
for each blob to help identify the original version that
|
||||||
the patch applies to. When this flag is given, and if
|
the patch applies to. When this flag is given, and if
|
||||||
the original version of the blob is available locally,
|
the original versions of the blobs is available locally,
|
||||||
outputs information about them to the standard output.
|
builds a temporary index containing those blobs.
|
||||||
|
+
|
||||||
|
When a pure mode change is encountered (which has no index information),
|
||||||
|
the information is read from the current index instead.
|
||||||
|
|
||||||
-R, --reverse::
|
-R, --reverse::
|
||||||
Apply the patch in reverse.
|
Apply the patch in reverse.
|
||||||
|
@ -10,7 +10,8 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git-archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
'git-archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
||||||
[--remote=<repo>] <tree-ish> [path...]
|
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
|
||||||
|
[path...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -52,6 +53,10 @@ OPTIONS
|
|||||||
Instead of making a tar archive from local repository,
|
Instead of making a tar archive from local repository,
|
||||||
retrieve a tar archive from a remote repository.
|
retrieve a tar archive from a remote repository.
|
||||||
|
|
||||||
|
--exec=<git-upload-archive>::
|
||||||
|
Used with --remote to specify the path to the
|
||||||
|
git-upload-archive executable on the remote side.
|
||||||
|
|
||||||
<tree-ish>::
|
<tree-ish>::
|
||||||
The tree or commit to produce an archive for.
|
The tree or commit to produce an archive for.
|
||||||
|
|
||||||
|
@ -26,6 +26,10 @@ It will start out with a head equal to the one given as <start-point>.
|
|||||||
If no <start-point> is given, the branch will be created with a head
|
If no <start-point> is given, the branch will be created with a head
|
||||||
equal to that of the currently checked out branch.
|
equal to that of the currently checked out branch.
|
||||||
|
|
||||||
|
Note that this will create the new branch, but it will not switch the
|
||||||
|
working tree to it; use "git checkout <newbranch>" to switch to the
|
||||||
|
new branch.
|
||||||
|
|
||||||
When a local branch is started off a remote branch, git can setup the
|
When a local branch is started off a remote branch, git can setup the
|
||||||
branch so that gitlink:git-pull[1] will appropriately merge from that
|
branch so that gitlink:git-pull[1] will appropriately merge from that
|
||||||
remote branch. If this behavior is desired, it is possible to make it
|
remote branch. If this behavior is desired, it is possible to make it
|
||||||
@ -91,6 +95,21 @@ OPTIONS
|
|||||||
--no-abbrev::
|
--no-abbrev::
|
||||||
Display the full sha1s in output listing rather than abbreviating them.
|
Display the full sha1s in output listing rather than abbreviating them.
|
||||||
|
|
||||||
|
--track::
|
||||||
|
Set up configuration so that git-pull will automatically
|
||||||
|
retrieve data from the remote branch. Use this if you always
|
||||||
|
pull from the same remote branch into the new branch, or if you
|
||||||
|
don't want to use "git pull <repository> <refspec>" explicitly. Set the
|
||||||
|
branch.autosetupmerge configuration variable to true if you
|
||||||
|
want git-checkout and git-branch to always behave as if
|
||||||
|
'--track' were given.
|
||||||
|
|
||||||
|
--no-track::
|
||||||
|
When -b is given and a branch is created off a remote branch,
|
||||||
|
set up configuration so that git-pull will not retrieve data
|
||||||
|
from the remote branch, ignoring the branch.autosetupmerge
|
||||||
|
configuration variable.
|
||||||
|
|
||||||
<branchname>::
|
<branchname>::
|
||||||
The name of the branch to create or delete.
|
The name of the branch to create or delete.
|
||||||
The new branch name must pass all checks defined by
|
The new branch name must pass all checks defined by
|
||||||
|
@ -103,14 +103,20 @@ We set a tag in R1 (lastR2bundle) after the previous such transport,
|
|||||||
and move it afterwards to help build the bundle.
|
and move it afterwards to help build the bundle.
|
||||||
|
|
||||||
in R1 on A:
|
in R1 on A:
|
||||||
|
|
||||||
|
------------
|
||||||
$ git-bundle create mybundle master ^lastR2bundle
|
$ git-bundle create mybundle master ^lastR2bundle
|
||||||
$ git tag -f lastR2bundle master
|
$ git tag -f lastR2bundle master
|
||||||
|
------------
|
||||||
|
|
||||||
(move mybundle from A to B by some mechanism)
|
(move mybundle from A to B by some mechanism)
|
||||||
|
|
||||||
in R2 on B:
|
in R2 on B:
|
||||||
|
|
||||||
|
------------
|
||||||
$ git-bundle verify mybundle
|
$ git-bundle verify mybundle
|
||||||
$ git-fetch mybundle refspec
|
$ git-fetch mybundle refspec
|
||||||
|
------------
|
||||||
|
|
||||||
where refspec is refInBundle:localRef
|
where refspec is refInBundle:localRef
|
||||||
|
|
||||||
@ -124,9 +130,11 @@ Also, with something like this in your config:
|
|||||||
You can first sneakernet the bundle file to ~/tmp/file.bdl and
|
You can first sneakernet the bundle file to ~/tmp/file.bdl and
|
||||||
then these commands:
|
then these commands:
|
||||||
|
|
||||||
|
------------
|
||||||
$ git ls-remote bundle
|
$ git ls-remote bundle
|
||||||
$ git fetch bundle
|
$ git fetch bundle
|
||||||
$ git pull bundle
|
$ git pull bundle
|
||||||
|
------------
|
||||||
|
|
||||||
would treat it as if it is talking with a remote side over the
|
would treat it as if it is talking with a remote side over the
|
||||||
network.
|
network.
|
||||||
|
@ -50,7 +50,9 @@ OPTIONS
|
|||||||
--track::
|
--track::
|
||||||
When -b is given and a branch is created off a remote branch,
|
When -b is given and a branch is created off a remote branch,
|
||||||
set up configuration so that git-pull will automatically
|
set up configuration so that git-pull will automatically
|
||||||
retrieve data from the remote branch. Set the
|
retrieve data from the remote branch. Use this if you always
|
||||||
|
pull from the same remote branch into the new branch, or if you
|
||||||
|
don't want to use "git pull <repository> <refspec>" explicitly. Set the
|
||||||
branch.autosetupmerge configuration variable to true if you
|
branch.autosetupmerge configuration variable to true if you
|
||||||
want git-checkout and git-branch to always behave as if
|
want git-checkout and git-branch to always behave as if
|
||||||
'--track' were given.
|
'--track' were given.
|
||||||
|
@ -125,7 +125,7 @@ $ git diff topic...master <3>
|
|||||||
+
|
+
|
||||||
<1> Changes between the tips of the topic and the master branches.
|
<1> Changes between the tips of the topic and the master branches.
|
||||||
<2> Same as above.
|
<2> Same as above.
|
||||||
<3> Changes that occured on the master branch since when the topic
|
<3> Changes that occurred on the master branch since when the topic
|
||||||
branch was started off it.
|
branch was started off it.
|
||||||
|
|
||||||
Limiting the diff output::
|
Limiting the diff output::
|
||||||
|
@ -100,6 +100,11 @@ In any case, a field name that refers to a field inapplicable to
|
|||||||
the object referred by the ref does not cause an error. It
|
the object referred by the ref does not cause an error. It
|
||||||
returns an empty string instead.
|
returns an empty string instead.
|
||||||
|
|
||||||
|
As a special case for the date-type fields, you may specify a format for
|
||||||
|
the date by adding one of `:default`, `:relative`, `:short`, `:local`,
|
||||||
|
`:iso8601` or `:rfc2822` to the end of the fieldname; e.g.
|
||||||
|
`%(taggerdate:relative)`.
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
--------
|
--------
|
||||||
|
@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-gc' [--prune] [--aggressive]
|
'git-gc' [--prune] [--aggressive] [--auto]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -43,6 +43,20 @@ OPTIONS
|
|||||||
persistent, so this option only needs to be used occasionally; every
|
persistent, so this option only needs to be used occasionally; every
|
||||||
few hundred changesets or so.
|
few hundred changesets or so.
|
||||||
|
|
||||||
|
--auto::
|
||||||
|
With this option, `git gc` checks if there are too many
|
||||||
|
loose objects in the repository and runs
|
||||||
|
gitlink:git-repack[1] with `-d -l` option to pack them.
|
||||||
|
The threshold for loose objects is set with `gc.auto` configuration
|
||||||
|
variable, and can be disabled by setting it to 0. Some
|
||||||
|
Porcelain commands use this after they perform operation
|
||||||
|
that could create many loose objects automatically.
|
||||||
|
Additionally, when there are too many packs are present,
|
||||||
|
they are consolidated into one larger pack by running
|
||||||
|
the `git-repack` command with `-A` option. The
|
||||||
|
threshold for number of packs is set with
|
||||||
|
`gc.autopacklimit` configuration variable.
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ OPTIONS
|
|||||||
a default name determined from the pack content. If
|
a default name determined from the pack content. If
|
||||||
<pack-file> is not specified consider using --keep to
|
<pack-file> is not specified consider using --keep to
|
||||||
prevent a race condition between this process and
|
prevent a race condition between this process and
|
||||||
gitlink::git-repack[1] .
|
gitlink::git-repack[1].
|
||||||
|
|
||||||
--fix-thin::
|
--fix-thin::
|
||||||
It is possible for gitlink:git-pack-objects[1] to build
|
It is possible for gitlink:git-pack-objects[1] to build
|
||||||
|
@ -27,7 +27,7 @@ OPTIONS
|
|||||||
The HTTP daemon command-line that will be executed.
|
The HTTP daemon command-line that will be executed.
|
||||||
Command-line options may be specified here, and the
|
Command-line options may be specified here, and the
|
||||||
configuration file will be added at the end of the command-line.
|
configuration file will be added at the end of the command-line.
|
||||||
Currently, lighttpd and apache2 are the only supported servers.
|
Currently lighttpd, apache2 and webrick are supported.
|
||||||
(Default: lighttpd)
|
(Default: lighttpd)
|
||||||
|
|
||||||
-m|--module-path::
|
-m|--module-path::
|
||||||
|
@ -65,7 +65,7 @@ $ git rev-parse not-lost-anymore
|
|||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano 濱野 純 <junkio@cox.net>
|
Written by Junio C Hamano <gitster@pobox.com>
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
|
@ -40,7 +40,7 @@ If "git-merge-index" is called with multiple <file>s (or -a) then it
|
|||||||
processes them in turn only stopping if merge returns a non-zero exit
|
processes them in turn only stopping if merge returns a non-zero exit
|
||||||
code.
|
code.
|
||||||
|
|
||||||
Typically this is run with the a script calling git's imitation of
|
Typically this is run with a script calling git's imitation of
|
||||||
the merge command from the RCS package.
|
the merge command from the RCS package.
|
||||||
|
|
||||||
A sample script called "git-merge-one-file" is included in the
|
A sample script called "git-merge-one-file" is included in the
|
||||||
|
@ -56,8 +56,12 @@ merge.verbosity::
|
|||||||
message if conflicts were detected. Level 1 outputs only
|
message if conflicts were detected. Level 1 outputs only
|
||||||
conflicts, 2 outputs conflicts and file changes. Level 5 and
|
conflicts, 2 outputs conflicts and file changes. Level 5 and
|
||||||
above outputs debugging information. The default is level 2.
|
above outputs debugging information. The default is level 2.
|
||||||
Can be overriden by 'GIT_MERGE_VERBOSITY' environment variable.
|
Can be overridden by 'GIT_MERGE_VERBOSITY' environment variable.
|
||||||
|
|
||||||
|
branch.<name>.mergeoptions::
|
||||||
|
Sets default options for merging into branch <name>. The syntax and
|
||||||
|
supported options are equal to that of git-merge, but option values
|
||||||
|
containing whitespace characters are currently not supported.
|
||||||
|
|
||||||
HOW MERGE WORKS
|
HOW MERGE WORKS
|
||||||
---------------
|
---------------
|
||||||
|
@ -25,16 +25,16 @@ is efficient to access. The packed archive format (.pack) is
|
|||||||
designed to be unpackable without having anything else, but for
|
designed to be unpackable without having anything else, but for
|
||||||
random access, accompanied with the pack index file (.idx).
|
random access, accompanied with the pack index file (.idx).
|
||||||
|
|
||||||
|
Placing both in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
|
||||||
|
any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
|
||||||
|
enables git to read from such an archive.
|
||||||
|
|
||||||
'git-unpack-objects' command can read the packed archive and
|
'git-unpack-objects' command can read the packed archive and
|
||||||
expand the objects contained in the pack into "one-file
|
expand the objects contained in the pack into "one-file
|
||||||
one-object" format; this is typically done by the smart-pull
|
one-object" format; this is typically done by the smart-pull
|
||||||
commands when a pack is created on-the-fly for efficient network
|
commands when a pack is created on-the-fly for efficient network
|
||||||
transport by their peers.
|
transport by their peers.
|
||||||
|
|
||||||
Placing both in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
|
|
||||||
any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
|
|
||||||
enables git to read from such an archive.
|
|
||||||
|
|
||||||
In a packed archive, an object is either stored as a compressed
|
In a packed archive, an object is either stored as a compressed
|
||||||
whole, or as a difference from some other object. The latter is
|
whole, or as a difference from some other object. The latter is
|
||||||
often called a delta.
|
often called a delta.
|
||||||
|
@ -13,7 +13,7 @@ SYNOPSIS
|
|||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
This program search the `$GIT_OBJECT_DIR` for all objects that currently
|
This program searches the `$GIT_OBJECT_DIR` for all objects that currently
|
||||||
exist in a pack file as well as the independent object directories.
|
exist in a pack file as well as the independent object directories.
|
||||||
|
|
||||||
All such extra objects are removed.
|
All such extra objects are removed.
|
||||||
|
@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git-push' [--all] [--tags] [--receive-pack=<git-receive-pack>]
|
'git-push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
|
||||||
[--repo=all] [-f | --force] [-v] [<repository> <refspec>...]
|
[--repo=all] [-f | --force] [-v] [<repository> <refspec>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -63,6 +63,9 @@ the remote repository.
|
|||||||
Instead of naming each ref to push, specifies that all
|
Instead of naming each ref to push, specifies that all
|
||||||
refs under `$GIT_DIR/refs/heads/` be pushed.
|
refs under `$GIT_DIR/refs/heads/` be pushed.
|
||||||
|
|
||||||
|
\--dry-run::
|
||||||
|
Do everything except actually send the updates.
|
||||||
|
|
||||||
\--tags::
|
\--tags::
|
||||||
All refs under `$GIT_DIR/refs/tags` are pushed, in
|
All refs under `$GIT_DIR/refs/tags` are pushed, in
|
||||||
addition to refspecs explicitly listed on the command
|
addition to refspecs explicitly listed on the command
|
||||||
|
@ -298,7 +298,7 @@ rebasing.
|
|||||||
If you want to fold two or more commits into one, replace the command
|
If you want to fold two or more commits into one, replace the command
|
||||||
"pick" with "squash" for the second and subsequent commit. If the
|
"pick" with "squash" for the second and subsequent commit. If the
|
||||||
commits had different authors, it will attribute the squashed commit to
|
commits had different authors, it will attribute the squashed commit to
|
||||||
the author of the last commit.
|
the author of the first commit.
|
||||||
|
|
||||||
In both cases, or when a "pick" does not succeed (because of merge
|
In both cases, or when a "pick" does not succeed (because of merge
|
||||||
errors), the loop will stop to let you fix things, and you can continue
|
errors), the loop will stop to let you fix things, and you can continue
|
||||||
|
@ -16,7 +16,7 @@ The command takes various subcommands, and different options
|
|||||||
depending on the subcommand:
|
depending on the subcommand:
|
||||||
|
|
||||||
[verse]
|
[verse]
|
||||||
git reflog expire [--dry-run] [--stale-fix]
|
git reflog expire [--dry-run] [--stale-fix] [--verbose]
|
||||||
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
||||||
|
|
||||||
git reflog [show] [log-options]
|
git reflog [show] [log-options]
|
||||||
@ -68,6 +68,9 @@ them.
|
|||||||
--all::
|
--all::
|
||||||
Instead of listing <refs> explicitly, prune all refs.
|
Instead of listing <refs> explicitly, prune all refs.
|
||||||
|
|
||||||
|
--verbose::
|
||||||
|
Print extra information on screen.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <junkio@cox.net>
|
Written by Junio C Hamano <junkio@cox.net>
|
||||||
|
@ -11,6 +11,7 @@ SYNOPSIS
|
|||||||
[verse]
|
[verse]
|
||||||
'git-remote'
|
'git-remote'
|
||||||
'git-remote' add [-t <branch>] [-m <branch>] [-f] [--mirror] <name> <url>
|
'git-remote' add [-t <branch>] [-m <branch>] [-f] [--mirror] <name> <url>
|
||||||
|
'git-remote' rm <name>
|
||||||
'git-remote' show <name>
|
'git-remote' show <name>
|
||||||
'git-remote' prune <name>
|
'git-remote' prune <name>
|
||||||
'git-remote' update [group]
|
'git-remote' update [group]
|
||||||
@ -50,6 +51,11 @@ In mirror mode, enabled with `--mirror`, the refs will not be stored
|
|||||||
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
|
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
|
||||||
only makes sense in bare repositories.
|
only makes sense in bare repositories.
|
||||||
|
|
||||||
|
'rm'::
|
||||||
|
|
||||||
|
Remove the remote named <name>. All remote tracking branches and
|
||||||
|
configuration settings for the remote are removed.
|
||||||
|
|
||||||
'show'::
|
'show'::
|
||||||
|
|
||||||
Gives some information about the remote <name>.
|
Gives some information about the remote <name>.
|
||||||
|
@ -91,6 +91,11 @@ The --cc option must be repeated for each user you want on the cc list.
|
|||||||
`/usr/lib/sendmail` if such program is available, or
|
`/usr/lib/sendmail` if such program is available, or
|
||||||
`localhost` otherwise.
|
`localhost` otherwise.
|
||||||
|
|
||||||
|
--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, --smtp-pass::
|
--smtp-user, --smtp-pass::
|
||||||
Username and password for SMTP-AUTH. Defaults are the values of
|
Username and password for SMTP-AUTH. Defaults are the values of
|
||||||
the configuration values 'sendemail.smtpuser' and
|
the configuration values 'sendemail.smtpuser' and
|
||||||
|
@ -8,7 +8,7 @@ git-send-pack - Push objects over git protocol to another repository
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-send-pack' [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]
|
'git-send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -34,6 +34,9 @@ OPTIONS
|
|||||||
Instead of explicitly specifying which refs to update,
|
Instead of explicitly specifying which refs to update,
|
||||||
update all heads that locally exist.
|
update all heads that locally exist.
|
||||||
|
|
||||||
|
\--dry-run::
|
||||||
|
Do everything except actually send the updates.
|
||||||
|
|
||||||
\--force::
|
\--force::
|
||||||
Usually, the command refuses to update a remote ref that
|
Usually, the command refuses to update a remote ref that
|
||||||
is not an ancestor of the local ref used to overwrite it.
|
is not an ancestor of the local ref used to overwrite it.
|
||||||
|
@ -57,13 +57,13 @@ stash@{1}: On master: 9cc0589... Add git-stash
|
|||||||
|
|
||||||
show [<stash>]::
|
show [<stash>]::
|
||||||
|
|
||||||
Show the changes recorded in the stash as a diff between the the
|
Show the changes recorded in the stash as a diff between the
|
||||||
stashed state and its original parent. When no `<stash>` is given,
|
stashed state and its original parent. When no `<stash>` is given,
|
||||||
shows the latest one. By default, the command shows the diffstat, but
|
shows the latest one. By default, the command shows the diffstat, but
|
||||||
it will accept any format known to `git-diff` (e.g., `git-stash show
|
it will accept any format known to `git-diff` (e.g., `git-stash show
|
||||||
-p stash@\{1}` to view the second most recent stash in patch form).
|
-p stash@\{1}` to view the second most recent stash in patch form).
|
||||||
|
|
||||||
apply [<stash>]::
|
apply [--index] [<stash>]::
|
||||||
|
|
||||||
Restore the changes recorded in the stash on top of the current
|
Restore the changes recorded in the stash on top of the current
|
||||||
working tree state. When no `<stash>` is given, applies the latest
|
working tree state. When no `<stash>` is given, applies the latest
|
||||||
@ -71,6 +71,11 @@ apply [<stash>]::
|
|||||||
+
|
+
|
||||||
This operation can fail with conflicts; you need to resolve them
|
This operation can fail with conflicts; you need to resolve them
|
||||||
by hand in the working tree.
|
by hand in the working tree.
|
||||||
|
+
|
||||||
|
If the `--index` option is used, then tries to reinstate not only the working
|
||||||
|
tree's changes, but also the index's ones. However, this can fail, when you
|
||||||
|
have conflicts (which are stored in the index, where you therefore can no
|
||||||
|
longer apply the changes as they were originally).
|
||||||
|
|
||||||
clear::
|
clear::
|
||||||
Remove all the stashed states. Note that those states will then
|
Remove all the stashed states. Note that those states will then
|
||||||
|
@ -21,6 +21,9 @@ add::
|
|||||||
repository is cloned at the specified path, added to the
|
repository is cloned at the specified path, added to the
|
||||||
changeset and registered in .gitmodules. If no path is
|
changeset and registered in .gitmodules. If no path is
|
||||||
specified, the path is deduced from the repository specification.
|
specified, the path is deduced from the repository specification.
|
||||||
|
If the repository url begins with ./ or ../, it is stored as
|
||||||
|
given but resolved as a relative path from the main project's
|
||||||
|
url when cloning.
|
||||||
|
|
||||||
status::
|
status::
|
||||||
Show the status of the submodules. This will print the SHA-1 of the
|
Show the status of the submodules. This will print the SHA-1 of the
|
||||||
|
@ -404,7 +404,7 @@ section because they affect the 'git-svn-id:' metadata line.
|
|||||||
BASIC EXAMPLES
|
BASIC EXAMPLES
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Tracking and contributing to a the trunk of a Subversion-managed project:
|
Tracking and contributing to the trunk of a Subversion-managed project:
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
# Clone a repo (like git clone):
|
# Clone a repo (like git clone):
|
||||||
|
@ -112,7 +112,7 @@ You really want to call the new version "X" too, 'even though'
|
|||||||
others have already seen the old one. So just use "git tag -f"
|
others have already seen the old one. So just use "git tag -f"
|
||||||
again, as if you hadn't already published the old one.
|
again, as if you hadn't already published the old one.
|
||||||
|
|
||||||
However, Git does *not* (and it should not)change tags behind
|
However, Git does *not* (and it should not) change tags behind
|
||||||
users back. So if somebody already got the old tag, doing a "git
|
users back. So if somebody already got the old tag, doing a "git
|
||||||
pull" on your tree shouldn't just make them overwrite the old
|
pull" on your tree shouldn't just make them overwrite the old
|
||||||
one.
|
one.
|
||||||
|
@ -46,6 +46,8 @@ Documentation for older releases are available here:
|
|||||||
* link:v1.5.3/git.html[documentation for release 1.5.3]
|
* link:v1.5.3/git.html[documentation for release 1.5.3]
|
||||||
|
|
||||||
* release notes for
|
* release notes for
|
||||||
|
link:RelNotes-1.5.3.4.txt[1.5.3.4],
|
||||||
|
link:RelNotes-1.5.3.3.txt[1.5.3.3],
|
||||||
link:RelNotes-1.5.3.2.txt[1.5.3.2],
|
link:RelNotes-1.5.3.2.txt[1.5.3.2],
|
||||||
link:RelNotes-1.5.3.1.txt[1.5.3.1].
|
link:RelNotes-1.5.3.1.txt[1.5.3.1].
|
||||||
|
|
||||||
@ -324,7 +326,7 @@ For a more complete list of ways to spell object names, see
|
|||||||
File/Directory Structure
|
File/Directory Structure
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Please see link:repository-layout.html[repository layout] document.
|
Please see the link:repository-layout.html[repository layout] document.
|
||||||
|
|
||||||
Read link:hooks.html[hooks] for more details about each hook.
|
Read link:hooks.html[hooks] for more details about each hook.
|
||||||
|
|
||||||
@ -334,7 +336,7 @@ Higher level SCMs may provide and manage additional information in the
|
|||||||
|
|
||||||
Terminology
|
Terminology
|
||||||
-----------
|
-----------
|
||||||
Please see link:glossary.html[glossary] document.
|
Please see the link:glossary.html[glossary] document.
|
||||||
|
|
||||||
|
|
||||||
Environment Variables
|
Environment Variables
|
||||||
|
@ -145,17 +145,6 @@ sign `$` upon checkout. Any byte sequence that begins with
|
|||||||
with `$Id$` upon check-in.
|
with `$Id$` upon check-in.
|
||||||
|
|
||||||
|
|
||||||
Interaction between checkin/checkout attributes
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
In the check-in codepath, the worktree file is first converted
|
|
||||||
with `ident` (if specified), and then with `crlf` (again, if
|
|
||||||
specified and applicable).
|
|
||||||
|
|
||||||
In the check-out codepath, the blob content is first converted
|
|
||||||
with `crlf`, and then `ident`.
|
|
||||||
|
|
||||||
|
|
||||||
`filter`
|
`filter`
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
@ -175,11 +164,10 @@ but makes the filter a no-op passthru.
|
|||||||
The content filtering is done to massage the content into a
|
The content filtering is done to massage the content into a
|
||||||
shape that is more convenient for the platform, filesystem, and
|
shape that is more convenient for the platform, filesystem, and
|
||||||
the user to use. The keyword here is "more convenient" and not
|
the user to use. The keyword here is "more convenient" and not
|
||||||
"turning something unusable into usable". In other words, it is
|
"turning something unusable into usable". In other words, the
|
||||||
"hanging yourself because we gave you a long rope" if your
|
intent is that if someone unsets the filter driver definition,
|
||||||
project uses filtering mechanism in such a way that it makes
|
or does not have the appropriate filter program, the project
|
||||||
your project unusable unless the checkout is done with a
|
should still be usable.
|
||||||
specific filter in effect.
|
|
||||||
|
|
||||||
|
|
||||||
Interaction between checkin/checkout attributes
|
Interaction between checkin/checkout attributes
|
||||||
|
@ -26,7 +26,7 @@ precedence, the last matching pattern decides the outcome):
|
|||||||
|
|
||||||
* Patterns read from a `.gitignore` file in the same directory
|
* Patterns read from a `.gitignore` file in the same directory
|
||||||
as the path, or in any parent directory, with patterns in the
|
as the path, or in any parent directory, with patterns in the
|
||||||
higher level files (up to the root) being overriden by those in
|
higher level files (up to the root) being overridden by those in
|
||||||
lower level files down to the directory containing the file.
|
lower level files down to the directory containing the file.
|
||||||
These patterns match relative to the location of the
|
These patterns match relative to the location of the
|
||||||
`.gitignore` file. A project normally includes such
|
`.gitignore` file. A project normally includes such
|
||||||
|
@ -52,8 +52,8 @@ GIT Glossary
|
|||||||
[[def_cherry-picking]]cherry-picking::
|
[[def_cherry-picking]]cherry-picking::
|
||||||
In <<def_SCM,SCM>> jargon, "cherry pick" means to choose a subset of
|
In <<def_SCM,SCM>> jargon, "cherry pick" means to choose a subset of
|
||||||
changes out of a series of changes (typically commits) and record them
|
changes out of a series of changes (typically commits) and record them
|
||||||
as a new series of changes on top of different codebase. In GIT, this is
|
as a new series of changes on top of a different codebase. In GIT, this is
|
||||||
performed by "git cherry-pick" command to extract the change introduced
|
performed by the "git cherry-pick" command to extract the change introduced
|
||||||
by an existing <<def_commit,commit>> and to record it based on the tip
|
by an existing <<def_commit,commit>> and to record it based on the tip
|
||||||
of the current <<def_branch,branch>> as a new commit.
|
of the current <<def_branch,branch>> as a new commit.
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ This commit is referred to as a "merge commit", or sometimes just a
|
|||||||
[[def_pickaxe]]pickaxe::
|
[[def_pickaxe]]pickaxe::
|
||||||
The term <<def_pickaxe,pickaxe>> refers to an option to the diffcore
|
The term <<def_pickaxe,pickaxe>> refers to an option to the diffcore
|
||||||
routines that help select changes that add or delete a given text
|
routines that help select changes that add or delete a given text
|
||||||
string. With the --pickaxe-all option, it can be used to view the full
|
string. With the `--pickaxe-all` option, it can be used to view the full
|
||||||
<<def_changeset,changeset>> that introduced or removed, say, a
|
<<def_changeset,changeset>> that introduced or removed, say, a
|
||||||
particular line of text. See gitlink:git-diff[1].
|
particular line of text. See gitlink:git-diff[1].
|
||||||
|
|
||||||
@ -301,8 +301,8 @@ This commit is referred to as a "merge commit", or sometimes just a
|
|||||||
[[def_push]]push::
|
[[def_push]]push::
|
||||||
Pushing a <<def_branch,branch>> means to get the branch's
|
Pushing a <<def_branch,branch>> means to get the branch's
|
||||||
<<def_head_ref,head ref>> from a remote <<def_repository,repository>>,
|
<<def_head_ref,head ref>> from a remote <<def_repository,repository>>,
|
||||||
find out if it is an ancestor to the branch's local
|
find out if it is a direct ancestor to the branch's local
|
||||||
head ref is a direct, and in that case, putting all
|
head ref, and in that case, putting all
|
||||||
objects, which are <<def_reachable,reachable>> from the local
|
objects, which are <<def_reachable,reachable>> from the local
|
||||||
head ref, and which are missing from the remote
|
head ref, and which are missing from the remote
|
||||||
repository, into the remote
|
repository, into the remote
|
||||||
@ -347,7 +347,7 @@ This commit is referred to as a "merge commit", or sometimes just a
|
|||||||
it as my origin branch head". And `git push
|
it as my origin branch head". And `git push
|
||||||
$URL refs/heads/master:refs/heads/to-upstream` means "publish my
|
$URL refs/heads/master:refs/heads/to-upstream` means "publish my
|
||||||
master branch head as to-upstream branch at $URL". See also
|
master branch head as to-upstream branch at $URL". See also
|
||||||
gitlink:git-push[1]
|
gitlink:git-push[1].
|
||||||
|
|
||||||
[[def_repository]]repository::
|
[[def_repository]]repository::
|
||||||
A collection of <<def_ref,refs>> together with an
|
A collection of <<def_ref,refs>> together with an
|
||||||
|
@ -87,6 +87,33 @@ parameter, and is invoked after a commit is made.
|
|||||||
This hook is meant primarily for notification, and cannot affect
|
This hook is meant primarily for notification, and cannot affect
|
||||||
the outcome of `git-commit`.
|
the outcome of `git-commit`.
|
||||||
|
|
||||||
|
post-checkout
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This hook is invoked when a `git-checkout` is run after having updated the
|
||||||
|
worktree. The hook is given three parameters: the ref of the previous HEAD,
|
||||||
|
the ref of the new HEAD (which may or may not have changed), and a flag
|
||||||
|
indicating whether the checkout was a branch checkout (changing branches,
|
||||||
|
flag=1) or a file checkout (retrieving a file from the index, flag=0).
|
||||||
|
This hook cannot affect the outcome of `git-checkout`.
|
||||||
|
|
||||||
|
This hook can be used to perform repository validity checks, auto-display
|
||||||
|
differences from the previous HEAD if different, or set working dir metadata
|
||||||
|
properties.
|
||||||
|
|
||||||
|
post-merge
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This hook is invoked by `git-merge`, which happens when a `git pull`
|
||||||
|
is done on a local repository. The hook takes a single parameter, a status
|
||||||
|
flag specifying whether or not the merge being done was a squash merge.
|
||||||
|
This hook cannot affect the outcome of `git-merge`.
|
||||||
|
|
||||||
|
This hook can be used in conjunction with a corresponding pre-commit hook to
|
||||||
|
save and restore any form of metadata associated with the working tree
|
||||||
|
(eg: permissions/ownership, ACLS, etc). See contrib/hooks/setgitperms.perl
|
||||||
|
for an example of how to do this.
|
||||||
|
|
||||||
[[pre-receive]]
|
[[pre-receive]]
|
||||||
pre-receive
|
pre-receive
|
||||||
-----------
|
-----------
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
not autocommit, to give the user a chance to inspect and
|
not autocommit, to give the user a chance to inspect and
|
||||||
further tweak the merge result before committing.
|
further tweak the merge result before committing.
|
||||||
|
|
||||||
|
--commit::
|
||||||
|
Perform the merge and commit the result. This option can
|
||||||
|
be used to override --no-commit.
|
||||||
|
|
||||||
--squash::
|
--squash::
|
||||||
Produce the working tree and index state as if a real
|
Produce the working tree and index state as if a real
|
||||||
merge happened, but do not actually make a commit or
|
merge happened, but do not actually make a commit or
|
||||||
@ -19,6 +23,19 @@
|
|||||||
top of the current branch whose effect is the same as
|
top of the current branch whose effect is the same as
|
||||||
merging another branch (or more in case of an octopus).
|
merging another branch (or more in case of an octopus).
|
||||||
|
|
||||||
|
--no-squash::
|
||||||
|
Perform the merge and commit the result. This option can
|
||||||
|
be used to override --squash.
|
||||||
|
|
||||||
|
--no-ff::
|
||||||
|
Generate a merge commit even if the merge resolved as a
|
||||||
|
fast-forward.
|
||||||
|
|
||||||
|
--ff::
|
||||||
|
Do not generate a merge commit if the merge resolved as
|
||||||
|
a fast-forward, only update the branch pointer. This is
|
||||||
|
the default behavior of git-merge.
|
||||||
|
|
||||||
-s <strategy>, \--strategy=<strategy>::
|
-s <strategy>, \--strategy=<strategy>::
|
||||||
Use the given merge strategy; can be supplied more than
|
Use the given merge strategy; can be supplied more than
|
||||||
once to specify them in the order they should be tried.
|
once to specify them in the order they should be tried.
|
||||||
|
@ -369,6 +369,11 @@ shorthand:
|
|||||||
The full name is occasionally useful if, for example, there ever
|
The full name is occasionally useful if, for example, there ever
|
||||||
exists a tag and a branch with the same name.
|
exists a tag and a branch with the same name.
|
||||||
|
|
||||||
|
(Newly created refs are actually stored in the .git/refs directory,
|
||||||
|
under the path given by their name. However, for efficiency reasons
|
||||||
|
they may also be packed together in a single file; see
|
||||||
|
gitlink:git-pack-refs[1]).
|
||||||
|
|
||||||
As another useful shortcut, the "HEAD" of a repository can be referred
|
As another useful shortcut, the "HEAD" of a repository can be referred
|
||||||
to just using the name of that repository. So, for example, "origin"
|
to just using the name of that repository. So, for example, "origin"
|
||||||
is usually a shortcut for the HEAD branch in the repository "origin".
|
is usually a shortcut for the HEAD branch in the repository "origin".
|
||||||
@ -921,7 +926,7 @@ file such that it contained the given content either before or after the
|
|||||||
commit. You can find out with this:
|
commit. You can find out with this:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git log --raw --abbrev=40 --pretty=oneline -- filename |
|
$ git log --raw --abbrev=40 --pretty=oneline |
|
||||||
grep -B 1 `git hash-object filename`
|
grep -B 1 `git hash-object filename`
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
@ -1490,7 +1495,7 @@ Ensuring good performance
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
On large repositories, git depends on compression to keep the history
|
On large repositories, git depends on compression to keep the history
|
||||||
information from taking up to much space on disk or in memory.
|
information from taking up too much space on disk or in memory.
|
||||||
|
|
||||||
This compression is not performed automatically. Therefore you
|
This compression is not performed automatically. Therefore you
|
||||||
should occasionally run gitlink:git-gc[1]:
|
should occasionally run gitlink:git-gc[1]:
|
||||||
@ -1531,7 +1536,7 @@ dangling tree b24c2473f1fd3d91352a624795be026d64c8841f
|
|||||||
Dangling objects are not a problem. At worst they may take up a little
|
Dangling objects are not a problem. At worst they may take up a little
|
||||||
extra disk space. They can sometimes provide a last-resort method for
|
extra disk space. They can sometimes provide a last-resort method for
|
||||||
recovering lost work--see <<dangling-objects>> for details. However, if
|
recovering lost work--see <<dangling-objects>> for details. However, if
|
||||||
you wish, you can remove them with gitlink:git-prune[1] or the --prune
|
you wish, you can remove them with gitlink:git-prune[1] or the `--prune`
|
||||||
option to gitlink:git-gc[1]:
|
option to gitlink:git-gc[1]:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
@ -1550,7 +1555,7 @@ Recovering lost changes
|
|||||||
Reflogs
|
Reflogs
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
Say you modify a branch with gitlink:git-reset[1] --hard, and then
|
Say you modify a branch with `gitlink:git-reset[1] --hard`, and then
|
||||||
realize that the branch was the only reference you had to that point in
|
realize that the branch was the only reference you had to that point in
|
||||||
history.
|
history.
|
||||||
|
|
||||||
@ -1679,7 +1684,7 @@ $ git pull
|
|||||||
More generally, a branch that is created from a remote branch will pull
|
More generally, a branch that is created from a remote branch will pull
|
||||||
by default from that branch. See the descriptions of the
|
by default from that branch. See the descriptions of the
|
||||||
branch.<name>.remote and branch.<name>.merge options in
|
branch.<name>.remote and branch.<name>.merge options in
|
||||||
gitlink:git-config[1], and the discussion of the --track option in
|
gitlink:git-config[1], and the discussion of the `--track` option in
|
||||||
gitlink:git-checkout[1], to learn how to control these defaults.
|
gitlink:git-checkout[1], to learn how to control these defaults.
|
||||||
|
|
||||||
In addition to saving you keystrokes, "git pull" also helps you by
|
In addition to saving you keystrokes, "git pull" also helps you by
|
||||||
@ -1777,7 +1782,7 @@ $ git clone /path/to/repository
|
|||||||
$ git pull /path/to/other/repository
|
$ git pull /path/to/other/repository
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
or an ssh url:
|
or an ssh URL:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git clone ssh://yourhost/~you/repository
|
$ git clone ssh://yourhost/~you/repository
|
||||||
@ -1838,7 +1843,7 @@ Exporting a git repository via the git protocol
|
|||||||
This is the preferred method.
|
This is the preferred method.
|
||||||
|
|
||||||
If someone else administers the server, they should tell you what
|
If someone else administers the server, they should tell you what
|
||||||
directory to put the repository in, and what git:// url it will appear
|
directory to put the repository in, and what git:// URL it will appear
|
||||||
at. You can then skip to the section
|
at. You can then skip to the section
|
||||||
"<<pushing-changes-to-a-public-repository,Pushing changes to a public
|
"<<pushing-changes-to-a-public-repository,Pushing changes to a public
|
||||||
repository>>", below.
|
repository>>", below.
|
||||||
@ -1875,8 +1880,8 @@ $ chmod a+x hooks/post-update
|
|||||||
gitlink:git-update-server-info[1], and the documentation
|
gitlink:git-update-server-info[1], and the documentation
|
||||||
link:hooks.html[Hooks used by git].)
|
link:hooks.html[Hooks used by git].)
|
||||||
|
|
||||||
Advertise the url of proj.git. Anybody else should then be able to
|
Advertise the URL of proj.git. Anybody else should then be able to
|
||||||
clone or pull from that url, for example with a command line like:
|
clone or pull from that URL, for example with a command line like:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git clone http://yourserver.com/~you/proj.git
|
$ git clone http://yourserver.com/~you/proj.git
|
||||||
@ -1915,7 +1920,7 @@ As with git-fetch, git-push will complain if this does not result in
|
|||||||
a <<fast-forwards,fast forward>>. Normally this is a sign of
|
a <<fast-forwards,fast forward>>. Normally this is a sign of
|
||||||
something wrong. However, if you are sure you know what you're
|
something wrong. However, if you are sure you know what you're
|
||||||
doing, you may force git-push to perform the update anyway by
|
doing, you may force git-push to perform the update anyway by
|
||||||
proceeding the branch name by a plus sign:
|
preceding the branch name by a plus sign:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git push ssh://yourserver.com/~you/proj.git +master
|
$ git push ssh://yourserver.com/~you/proj.git +master
|
||||||
@ -2035,7 +2040,7 @@ $ git branch --track test origin/master
|
|||||||
$ git branch --track release origin/master
|
$ git branch --track release origin/master
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
These can be easily kept up to date using gitlink:git-pull[1]
|
These can be easily kept up to date using gitlink:git-pull[1].
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git checkout test && git pull
|
$ git checkout test && git pull
|
||||||
@ -2127,7 +2132,7 @@ changes are in a specific branch, use:
|
|||||||
$ git log linux..branchname | git-shortlog
|
$ git log linux..branchname | git-shortlog
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
To see whether it has already been merged into the test or release branches
|
To see whether it has already been merged into the test or release branches,
|
||||||
use:
|
use:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
@ -2140,12 +2145,12 @@ or
|
|||||||
$ git log release..branchname
|
$ git log release..branchname
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
(If this branch has not yet been merged you will see some log entries.
|
(If this branch has not yet been merged, you will see some log entries.
|
||||||
If it has been merged, then there will be no output.)
|
If it has been merged, then there will be no output.)
|
||||||
|
|
||||||
Once a patch completes the great cycle (moving from test to release,
|
Once a patch completes the great cycle (moving from test to release,
|
||||||
then pulled by Linus, and finally coming back into your local
|
then pulled by Linus, and finally coming back into your local
|
||||||
"origin/master" branch) the branch for this change is no longer needed.
|
"origin/master" branch), the branch for this change is no longer needed.
|
||||||
You detect this when the output from:
|
You detect this when the output from:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
@ -2189,9 +2194,9 @@ test|release)
|
|||||||
git checkout $1 && git pull . origin
|
git checkout $1 && git pull . origin
|
||||||
;;
|
;;
|
||||||
origin)
|
origin)
|
||||||
before=$(cat .git/refs/remotes/origin/master)
|
before=$(git rev-parse refs/remotes/origin/master)
|
||||||
git fetch origin
|
git fetch origin
|
||||||
after=$(cat .git/refs/remotes/origin/master)
|
after=$(git rev-parse refs/remotes/origin/master)
|
||||||
if [ $before != $after ]
|
if [ $before != $after ]
|
||||||
then
|
then
|
||||||
git log $before..$after | git shortlog
|
git log $before..$after | git shortlog
|
||||||
@ -2216,11 +2221,10 @@ usage()
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ ! -f .git/refs/heads/"$1" ]
|
git show-ref -q --verify -- refs/heads/"$1" || {
|
||||||
then
|
|
||||||
echo "Can't see branch <$1>" 1>&2
|
echo "Can't see branch <$1>" 1>&2
|
||||||
usage
|
usage
|
||||||
fi
|
}
|
||||||
|
|
||||||
case "$2" in
|
case "$2" in
|
||||||
test|release)
|
test|release)
|
||||||
@ -2251,7 +2255,7 @@ then
|
|||||||
git log test..release
|
git log test..release
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for branch in `ls .git/refs/heads`
|
for branch in `git show-ref --heads | sed 's|^.*/||'`
|
||||||
do
|
do
|
||||||
if [ $branch = test -o $branch = release ]
|
if [ $branch = test -o $branch = release ]
|
||||||
then
|
then
|
||||||
@ -2408,7 +2412,7 @@ $ git rebase --continue
|
|||||||
|
|
||||||
and git will continue applying the rest of the patches.
|
and git will continue applying the rest of the patches.
|
||||||
|
|
||||||
At any point you may use the --abort option to abort this process and
|
At any point you may use the `--abort` option to abort this process and
|
||||||
return mywork to the state it had before you started the rebase:
|
return mywork to the state it had before you started the rebase:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
@ -2475,9 +2479,9 @@ $ git checkout -b mywork-new origin
|
|||||||
$ gitk origin..mywork &
|
$ gitk origin..mywork &
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
And browse through the list of patches in the mywork branch using gitk,
|
and browse through the list of patches in the mywork branch using gitk,
|
||||||
applying them (possibly in a different order) to mywork-new using
|
applying them (possibly in a different order) to mywork-new using
|
||||||
cherry-pick, and possibly modifying them as you go using commit --amend.
|
cherry-pick, and possibly modifying them as you go using `commit --amend`.
|
||||||
The gitlink:git-gui[1] command may also help as it allows you to
|
The gitlink:git-gui[1] command may also help as it allows you to
|
||||||
individually select diff hunks for inclusion in the index (by
|
individually select diff hunks for inclusion in the index (by
|
||||||
right-clicking on the diff hunk and choosing "Stage Hunk for Commit").
|
right-clicking on the diff hunk and choosing "Stage Hunk for Commit").
|
||||||
@ -2735,7 +2739,7 @@ others:
|
|||||||
|
|
||||||
- Git can quickly determine whether two objects are identical or not,
|
- Git can quickly determine whether two objects are identical or not,
|
||||||
just by comparing names.
|
just by comparing names.
|
||||||
- Since object names are computed the same way in ever repository, the
|
- Since object names are computed the same way in every repository, the
|
||||||
same content stored in two repositories will always be stored under
|
same content stored in two repositories will always be stored under
|
||||||
the same name.
|
the same name.
|
||||||
- Git can detect errors when it reads an object, by checking that the
|
- Git can detect errors when it reads an object, by checking that the
|
||||||
@ -2752,7 +2756,7 @@ There are four different types of objects: "blob", "tree", "commit", and
|
|||||||
"blob" objects into a directory structure. In addition, a tree object
|
"blob" objects into a directory structure. In addition, a tree object
|
||||||
can refer to other tree objects, thus creating a directory hierarchy.
|
can refer to other tree objects, thus creating a directory hierarchy.
|
||||||
- A <<def_commit_object,"commit" object>> ties such directory hierarchies
|
- A <<def_commit_object,"commit" object>> ties such directory hierarchies
|
||||||
together into a <<def_DAG,directed acyclic graph>> of revisions - each
|
together into a <<def_DAG,directed acyclic graph>> of revisions--each
|
||||||
commit contains the object name of exactly one tree designating the
|
commit contains the object name of exactly one tree designating the
|
||||||
directory hierarchy at the time of the commit. In addition, a commit
|
directory hierarchy at the time of the commit. In addition, a commit
|
||||||
refers to "parent" commit objects that describe the history of how we
|
refers to "parent" commit objects that describe the history of how we
|
||||||
@ -2852,8 +2856,7 @@ between two related tree objects, since it can ignore any entries with
|
|||||||
identical object names.
|
identical object names.
|
||||||
|
|
||||||
(Note: in the presence of submodules, trees may also have commits as
|
(Note: in the presence of submodules, trees may also have commits as
|
||||||
entries. See gitlink:git-submodule[1] and gitlink:gitmodules.txt[1]
|
entries. See <<submodules>> for documentation.)
|
||||||
for partial documentation.)
|
|
||||||
|
|
||||||
Note that the files all have mode 644 or 755: git actually only pays
|
Note that the files all have mode 644 or 755: git actually only pays
|
||||||
attention to the executable bit.
|
attention to the executable bit.
|
||||||
@ -2946,7 +2949,7 @@ nLE/L9aUXdWeTFPron96DLA=
|
|||||||
See the gitlink:git-tag[1] command to learn how to create and verify tag
|
See the gitlink:git-tag[1] command to learn how to create and verify tag
|
||||||
objects. (Note that gitlink:git-tag[1] can also be used to create
|
objects. (Note that gitlink:git-tag[1] can also be used to create
|
||||||
"lightweight tags", which are not tag objects at all, but just simple
|
"lightweight tags", which are not tag objects at all, but just simple
|
||||||
references in .git/refs/tags/).
|
references whose names begin with "refs/tags/").
|
||||||
|
|
||||||
[[pack-files]]
|
[[pack-files]]
|
||||||
How git stores objects efficiently: pack files
|
How git stores objects efficiently: pack files
|
||||||
@ -3026,7 +3029,7 @@ There are also other situations that cause dangling objects. For
|
|||||||
example, a "dangling blob" may arise because you did a "git add" of a
|
example, a "dangling blob" may arise because you did a "git add" of a
|
||||||
file, but then, before you actually committed it and made it part of the
|
file, but then, before you actually committed it and made it part of the
|
||||||
bigger picture, you changed something else in that file and committed
|
bigger picture, you changed something else in that file and committed
|
||||||
that *updated* thing - the old state that you added originally ends up
|
that *updated* thing--the old state that you added originally ends up
|
||||||
not being pointed to by any commit or tree, so it's now a dangling blob
|
not being pointed to by any commit or tree, so it's now a dangling blob
|
||||||
object.
|
object.
|
||||||
|
|
||||||
@ -3041,7 +3044,7 @@ up pointing to them, so they end up "dangling" in your repository.
|
|||||||
Generally, dangling objects aren't anything to worry about. They can
|
Generally, dangling objects aren't anything to worry about. They can
|
||||||
even be very useful: if you screw something up, the dangling objects can
|
even be very useful: if you screw something up, the dangling objects can
|
||||||
be how you recover your old tree (say, you did a rebase, and realized
|
be how you recover your old tree (say, you did a rebase, and realized
|
||||||
that you really didn't want to - you can look at what dangling objects
|
that you really didn't want to--you can look at what dangling objects
|
||||||
you have, and decide to reset your head to some old dangling state).
|
you have, and decide to reset your head to some old dangling state).
|
||||||
|
|
||||||
For commits, you can just use:
|
For commits, you can just use:
|
||||||
@ -3085,10 +3088,10 @@ $ git prune
|
|||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
and they'll be gone. But you should only run "git prune" on a quiescent
|
and they'll be gone. But you should only run "git prune" on a quiescent
|
||||||
repository - it's kind of like doing a filesystem fsck recovery: you
|
repository--it's kind of like doing a filesystem fsck recovery: you
|
||||||
don't want to do that while the filesystem is mounted.
|
don't want to do that while the filesystem is mounted.
|
||||||
|
|
||||||
(The same is true of "git-fsck" itself, btw - but since
|
(The same is true of "git-fsck" itself, btw, but since
|
||||||
git-fsck never actually *changes* the repository, it just reports
|
git-fsck never actually *changes* the repository, it just reports
|
||||||
on what it found, git-fsck itself is never "dangerous" to run.
|
on what it found, git-fsck itself is never "dangerous" to run.
|
||||||
Running it while somebody is actually changing the repository can cause
|
Running it while somebody is actually changing the repository can cause
|
||||||
@ -3155,6 +3158,241 @@ a tree which you are in the process of working on.
|
|||||||
If you blow the index away entirely, you generally haven't lost any
|
If you blow the index away entirely, you generally haven't lost any
|
||||||
information as long as you have the name of the tree that it described.
|
information as long as you have the name of the tree that it described.
|
||||||
|
|
||||||
|
[[submodules]]
|
||||||
|
Submodules
|
||||||
|
==========
|
||||||
|
|
||||||
|
Large projects are often composed of smaller, self-contained modules. For
|
||||||
|
example, an embedded Linux distribution's source tree would include every
|
||||||
|
piece of software in the distribution with some local modifications; a movie
|
||||||
|
player might need to build against a specific, known-working version of a
|
||||||
|
decompression library; several independent programs might all share the same
|
||||||
|
build scripts.
|
||||||
|
|
||||||
|
With centralized revision control systems this is often accomplished by
|
||||||
|
including every module in one single repository. Developers can check out
|
||||||
|
all modules or only the modules they need to work with. They can even modify
|
||||||
|
files across several modules in a single commit while moving things around
|
||||||
|
or updating APIs and translations.
|
||||||
|
|
||||||
|
Git does not allow partial checkouts, so duplicating this approach in Git
|
||||||
|
would force developers to keep a local copy of modules they are not
|
||||||
|
interested in touching. Commits in an enormous checkout would be slower
|
||||||
|
than you'd expect as Git would have to scan every directory for changes.
|
||||||
|
If modules have a lot of local history, clones would take forever.
|
||||||
|
|
||||||
|
On the plus side, distributed revision control systems can much better
|
||||||
|
integrate with external sources. In a centralized model, a single arbitrary
|
||||||
|
snapshot of the external project is exported from its own revision control
|
||||||
|
and then imported into the local revision control on a vendor branch. All
|
||||||
|
the history is hidden. With distributed revision control you can clone the
|
||||||
|
entire external history and much more easily follow development and re-merge
|
||||||
|
local changes.
|
||||||
|
|
||||||
|
Git's submodule support allows a repository to contain, as a subdirectory, a
|
||||||
|
checkout of an external project. Submodules maintain their own identity;
|
||||||
|
the submodule support just stores the submodule repository location and
|
||||||
|
commit ID, so other developers who clone the containing project
|
||||||
|
("superproject") can easily clone all the submodules at the same revision.
|
||||||
|
Partial checkouts of the superproject are possible: you can tell Git to
|
||||||
|
clone none, some or all of the submodules.
|
||||||
|
|
||||||
|
The gitlink:git-submodule[1] command is available since Git 1.5.3. Users
|
||||||
|
with Git 1.5.2 can look up the submodule commits in the repository and
|
||||||
|
manually check them out; earlier versions won't recognize the submodules at
|
||||||
|
all.
|
||||||
|
|
||||||
|
To see how submodule support works, create (for example) four example
|
||||||
|
repositories that can be used later as a submodule:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ mkdir ~/git
|
||||||
|
$ cd ~/git
|
||||||
|
$ for i in a b c d
|
||||||
|
do
|
||||||
|
mkdir $i
|
||||||
|
cd $i
|
||||||
|
git init
|
||||||
|
echo "module $i" > $i.txt
|
||||||
|
git add $i.txt
|
||||||
|
git commit -m "Initial commit, submodule $i"
|
||||||
|
cd ..
|
||||||
|
done
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
Now create the superproject and add all the submodules:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ mkdir super
|
||||||
|
$ cd super
|
||||||
|
$ git init
|
||||||
|
$ for i in a b c d
|
||||||
|
do
|
||||||
|
git submodule add ~/git/$i
|
||||||
|
done
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
NOTE: Do not use local URLs here if you plan to publish your superproject!
|
||||||
|
|
||||||
|
See what files `git submodule` created:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ ls -a
|
||||||
|
. .. .git .gitmodules a b c d
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
The `git submodule add` command does a couple of things:
|
||||||
|
|
||||||
|
- It clones the submodule under the current directory and by default checks out
|
||||||
|
the master branch.
|
||||||
|
- It adds the submodule's clone path to the gitlink:gitmodules[5] file and
|
||||||
|
adds this file to the index, ready to be committed.
|
||||||
|
- It adds the submodule's current commit ID to the index, ready to be
|
||||||
|
committed.
|
||||||
|
|
||||||
|
Commit the superproject:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ git commit -m "Add submodules a, b, c and d."
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
Now clone the superproject:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ cd ..
|
||||||
|
$ git clone super cloned
|
||||||
|
$ cd cloned
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
The submodule directories are there, but they're empty:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ ls -a a
|
||||||
|
. ..
|
||||||
|
$ git submodule status
|
||||||
|
-d266b9873ad50488163457f025db7cdd9683d88b a
|
||||||
|
-e81d457da15309b4fef4249aba9b50187999670d b
|
||||||
|
-c1536a972b9affea0f16e0680ba87332dc059146 c
|
||||||
|
-d96249ff5d57de5de093e6baff9e0aafa5276a74 d
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
NOTE: The commit object names shown above would be different for you, but they
|
||||||
|
should match the HEAD commit object names of your repositories. You can check
|
||||||
|
it by running `git ls-remote ../a`.
|
||||||
|
|
||||||
|
Pulling down the submodules is a two-step process. First run `git submodule
|
||||||
|
init` to add the submodule repository URLs to `.git/config`:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ git submodule init
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
Now use `git submodule update` to clone the repositories and check out the
|
||||||
|
commits specified in the superproject:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ git submodule update
|
||||||
|
$ cd a
|
||||||
|
$ ls -a
|
||||||
|
. .. .git a.txt
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
One major difference between `git submodule update` and `git submodule add` is
|
||||||
|
that `git submodule update` checks out a specific commit, rather than the tip
|
||||||
|
of a branch. It's like checking out a tag: the head is detached, so you're not
|
||||||
|
working on a branch.
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ git branch
|
||||||
|
* (no branch)
|
||||||
|
master
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
If you want to make a change within a submodule and you have a detached head,
|
||||||
|
then you should create or checkout a branch, make your changes, publish the
|
||||||
|
change within the submodule, and then update the superproject to reference the
|
||||||
|
new commit:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ git checkout master
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ git checkout -b fix-up
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
then
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ echo "adding a line again" >> a.txt
|
||||||
|
$ git commit -a -m "Updated the submodule from within the superproject."
|
||||||
|
$ git push
|
||||||
|
$ cd ..
|
||||||
|
$ git diff
|
||||||
|
diff --git a/a b/a
|
||||||
|
index d266b98..261dfac 160000
|
||||||
|
--- a/a
|
||||||
|
+++ b/a
|
||||||
|
@@ -1 +1 @@
|
||||||
|
-Subproject commit d266b9873ad50488163457f025db7cdd9683d88b
|
||||||
|
+Subproject commit 261dfac35cb99d380eb966e102c1197139f7fa24
|
||||||
|
$ git add a
|
||||||
|
$ git commit -m "Updated submodule a."
|
||||||
|
$ git push
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
You have to run `git submodule update` after `git pull` if you want to update
|
||||||
|
submodules, too.
|
||||||
|
|
||||||
|
Pitfalls with submodules
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Always publish the submodule change before publishing the change to the
|
||||||
|
superproject that references it. If you forget to publish the submodule change,
|
||||||
|
others won't be able to clone the repository:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ cd ~/git/super/a
|
||||||
|
$ echo i added another line to this file >> a.txt
|
||||||
|
$ git commit -a -m "doing it wrong this time"
|
||||||
|
$ cd ..
|
||||||
|
$ git add a
|
||||||
|
$ git commit -m "Updated submodule a again."
|
||||||
|
$ git push
|
||||||
|
$ cd ~/git/cloned
|
||||||
|
$ git pull
|
||||||
|
$ git submodule update
|
||||||
|
error: pathspec '261dfac35cb99d380eb966e102c1197139f7fa24' did not match any file(s) known to git.
|
||||||
|
Did you forget to 'git add'?
|
||||||
|
Unable to checkout '261dfac35cb99d380eb966e102c1197139f7fa24' in submodule path 'a'
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
You also should not rewind branches in a submodule beyond commits that were
|
||||||
|
ever recorded in any superproject.
|
||||||
|
|
||||||
|
It's not safe to run `git submodule update` if you've made and committed
|
||||||
|
changes within a submodule without checking out a branch first. They will be
|
||||||
|
silently overwritten:
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
$ cat a.txt
|
||||||
|
module a
|
||||||
|
$ echo line added from private2 >> a.txt
|
||||||
|
$ git commit -a -m "line added inside private2"
|
||||||
|
$ cd ..
|
||||||
|
$ git submodule update
|
||||||
|
Submodule path 'a': checked out 'd266b9873ad50488163457f025db7cdd9683d88b'
|
||||||
|
$ cd a
|
||||||
|
$ cat a.txt
|
||||||
|
module a
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
NOTE: The changes are still visible in the submodule's reflog.
|
||||||
|
|
||||||
|
This is not the case if you did not commit your changes.
|
||||||
|
|
||||||
[[low-level-operations]]
|
[[low-level-operations]]
|
||||||
Low-level git operations
|
Low-level git operations
|
||||||
========================
|
========================
|
||||||
@ -3187,9 +3425,10 @@ The Workflow
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
High-level operations such as gitlink:git-commit[1],
|
High-level operations such as gitlink:git-commit[1],
|
||||||
gitlink:git-checkout[1] and git-reset[1] work by moving data between the
|
gitlink:git-checkout[1] and gitlink:git-reset[1] work by moving data
|
||||||
working tree, the index, and the object database. Git provides
|
between the working tree, the index, and the object database. Git
|
||||||
low-level operations which perform each of these steps individually.
|
provides low-level operations which perform each of these steps
|
||||||
|
individually.
|
||||||
|
|
||||||
Generally, all "git" operations work on the index file. Some operations
|
Generally, all "git" operations work on the index file. Some operations
|
||||||
work *purely* on the index file (showing the current state of the
|
work *purely* on the index file (showing the current state of the
|
||||||
@ -3244,7 +3483,7 @@ You write your current index file to a "tree" object with the program
|
|||||||
$ git write-tree
|
$ git write-tree
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
that doesn't come with any options - it will just write out the
|
that doesn't come with any options--it will just write out the
|
||||||
current index into the set of tree objects that describe that state,
|
current index into the set of tree objects that describe that state,
|
||||||
and it will return the name of the resulting top-level tree. You can
|
and it will return the name of the resulting top-level tree. You can
|
||||||
use that tree to re-generate the index at any time by going in the
|
use that tree to re-generate the index at any time by going in the
|
||||||
@ -3255,7 +3494,7 @@ object database -> index
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
You read a "tree" file from the object database, and use that to
|
You read a "tree" file from the object database, and use that to
|
||||||
populate (and overwrite - don't do this if your index contains any
|
populate (and overwrite--don't do this if your index contains any
|
||||||
unsaved state that you might want to restore later!) your current
|
unsaved state that you might want to restore later!) your current
|
||||||
index. Normal operation is just
|
index. Normal operation is just
|
||||||
|
|
||||||
@ -3303,7 +3542,7 @@ Tying it all together
|
|||||||
|
|
||||||
To commit a tree you have instantiated with "git-write-tree", you'd
|
To commit a tree you have instantiated with "git-write-tree", you'd
|
||||||
create a "commit" object that refers to that tree and the history
|
create a "commit" object that refers to that tree and the history
|
||||||
behind it - most notably the "parent" commits that preceded it in
|
behind it--most notably the "parent" commits that preceded it in
|
||||||
history.
|
history.
|
||||||
|
|
||||||
Normally a "commit" has one parent: the previous state of the tree
|
Normally a "commit" has one parent: the previous state of the tree
|
||||||
@ -3446,7 +3685,7 @@ Once you know the three trees you are going to merge (the one "original"
|
|||||||
tree, aka the common tree, and the two "result" trees, aka the branches
|
tree, aka the common tree, and the two "result" trees, aka the branches
|
||||||
you want to merge), you do a "merge" read into the index. This will
|
you want to merge), you do a "merge" read into the index. This will
|
||||||
complain if it has to throw away your old index contents, so you should
|
complain if it has to throw away your old index contents, so you should
|
||||||
make sure that you've committed those - in fact you would normally
|
make sure that you've committed those--in fact you would normally
|
||||||
always do a merge against your last commit (which should thus match what
|
always do a merge against your last commit (which should thus match what
|
||||||
you have in your current index anyway).
|
you have in your current index anyway).
|
||||||
|
|
||||||
@ -3466,7 +3705,7 @@ Merging multiple trees, continued
|
|||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
Sadly, many merges aren't trivial. If there are files that have
|
Sadly, many merges aren't trivial. If there are files that have
|
||||||
been added.moved or removed, or if both branches have modified the
|
been added, moved or removed, or if both branches have modified the
|
||||||
same file, you will be left with an index tree that contains "merge
|
same file, you will be left with an index tree that contains "merge
|
||||||
entries" in it. Such an index tree can 'NOT' be written out to a tree
|
entries" in it. Such an index tree can 'NOT' be written out to a tree
|
||||||
object, and you will have to resolve any such merge clashes using
|
object, and you will have to resolve any such merge clashes using
|
||||||
@ -3718,7 +3957,7 @@ Two things are interesting here:
|
|||||||
|
|
||||||
- `get_sha1()` returns 0 on _success_. This might surprise some new
|
- `get_sha1()` returns 0 on _success_. This might surprise some new
|
||||||
Git hackers, but there is a long tradition in UNIX to return different
|
Git hackers, but there is a long tradition in UNIX to return different
|
||||||
negative numbers in case of different errors -- and 0 on success.
|
negative numbers in case of different errors--and 0 on success.
|
||||||
|
|
||||||
- the variable `sha1` in the function signature of `get_sha1()` is `unsigned
|
- the variable `sha1` in the function signature of `get_sha1()` is `unsigned
|
||||||
char \*`, but is actually expected to be a pointer to `unsigned
|
char \*`, but is actually expected to be a pointer to `unsigned
|
||||||
@ -3823,7 +4062,7 @@ $ git branch new # create branch "new" starting at current HEAD
|
|||||||
$ git branch -d new # delete branch "new"
|
$ git branch -d new # delete branch "new"
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
Instead of basing new branch on current HEAD (the default), use:
|
Instead of basing a new branch on current HEAD (the default), use:
|
||||||
|
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
$ git branch new test # branch named "test"
|
$ git branch new test # branch named "test"
|
||||||
@ -4071,5 +4310,3 @@ Write a chapter on using plumbing and writing scripts.
|
|||||||
Alternates, clone -reference, etc.
|
Alternates, clone -reference, etc.
|
||||||
|
|
||||||
git unpack-objects -r for recovery
|
git unpack-objects -r for recovery
|
||||||
|
|
||||||
submodules
|
|
||||||
|
3
INSTALL
3
INSTALL
@ -79,6 +79,9 @@ Issues of note:
|
|||||||
- "perl" and POSIX-compliant shells are needed to use most of
|
- "perl" and POSIX-compliant shells are needed to use most of
|
||||||
the barebone Porcelainish scripts.
|
the barebone Porcelainish scripts.
|
||||||
|
|
||||||
|
- "cpio" is used by git-merge for saving and restoring the index,
|
||||||
|
and by git-clone when doing a local (possibly hardlinked) clone.
|
||||||
|
|
||||||
- Some platform specific issues are dealt with Makefile rules,
|
- Some platform specific issues are dealt with Makefile rules,
|
||||||
but depending on your specific installation, you may not
|
but depending on your specific installation, you may not
|
||||||
have all the libraries/tools needed, or you may have
|
have all the libraries/tools needed, or you may have
|
||||||
|
17
Makefile
17
Makefile
@ -232,7 +232,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
|||||||
|
|
||||||
# ... and all the rest that could be moved out of bindir to gitexecdir
|
# ... and all the rest that could be moved out of bindir to gitexecdir
|
||||||
PROGRAMS = \
|
PROGRAMS = \
|
||||||
git-convert-objects$X git-fetch-pack$X \
|
git-fetch-pack$X \
|
||||||
git-hash-object$X git-index-pack$X \
|
git-hash-object$X git-index-pack$X \
|
||||||
git-fast-import$X \
|
git-fast-import$X \
|
||||||
git-daemon$X \
|
git-daemon$X \
|
||||||
@ -808,7 +808,7 @@ perl/perl.mak: GIT-CFLAGS
|
|||||||
|
|
||||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||||
INSTLIBDIR=`$(MAKE) -C perl -s --no-print-directory instlibdir` && \
|
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
|
||||||
sed -e '1{' \
|
sed -e '1{' \
|
||||||
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
||||||
-e ' h' \
|
-e ' h' \
|
||||||
@ -939,6 +939,10 @@ tags:
|
|||||||
$(RM) tags
|
$(RM) tags
|
||||||
$(FIND) . -name '*.[hcS]' -print | xargs ctags -a
|
$(FIND) . -name '*.[hcS]' -print | xargs ctags -a
|
||||||
|
|
||||||
|
cscope:
|
||||||
|
$(RM) cscope*
|
||||||
|
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
|
||||||
|
|
||||||
### Detect prefix changes
|
### Detect prefix changes
|
||||||
TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
|
TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
|
||||||
$(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
|
$(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
|
||||||
@ -1080,14 +1084,17 @@ dist-doc:
|
|||||||
|
|
||||||
### Cleaning rules
|
### Cleaning rules
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
$(RM) configure
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
|
$(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
|
||||||
$(LIB_FILE) $(XDIFF_LIB)
|
$(LIB_FILE) $(XDIFF_LIB)
|
||||||
$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||||
$(RM) $(TEST_PROGRAMS)
|
$(RM) $(TEST_PROGRAMS)
|
||||||
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
|
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
|
||||||
$(RM) -r autom4te.cache
|
$(RM) -r autom4te.cache
|
||||||
$(RM) configure config.log config.mak.autogen config.mak.append config.status config.cache
|
$(RM) config.log config.mak.autogen config.mak.append config.status config.cache
|
||||||
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
|
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
|
||||||
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||||
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
|
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
|
||||||
@ -1103,7 +1110,7 @@ endif
|
|||||||
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
|
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
|
||||||
|
|
||||||
.PHONY: all install clean strip
|
.PHONY: all install clean strip
|
||||||
.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags .FORCE-GIT-CFLAGS
|
.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
|
||||||
|
|
||||||
### Check documentation
|
### Check documentation
|
||||||
#
|
#
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "strbuf.h"
|
|
||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "archive.h"
|
#include "archive.h"
|
||||||
@ -79,19 +78,6 @@ static void write_trailer(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strbuf_append_string(struct strbuf *sb, const char *s)
|
|
||||||
{
|
|
||||||
int slen = strlen(s);
|
|
||||||
int total = sb->len + slen;
|
|
||||||
if (total + 1 > sb->alloc) {
|
|
||||||
sb->buf = xrealloc(sb->buf, total + 1);
|
|
||||||
sb->alloc = total + 1;
|
|
||||||
}
|
|
||||||
memcpy(sb->buf + sb->len, s, slen);
|
|
||||||
sb->len = total;
|
|
||||||
sb->buf[total] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pax extended header records have the format "%u %s=%s\n". %u contains
|
* pax extended header records have the format "%u %s=%s\n". %u contains
|
||||||
* the size of the whole string (including the %u), the first %s is the
|
* the size of the whole string (including the %u), the first %s is the
|
||||||
@ -101,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)
|
|||||||
static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
|
static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
|
||||||
const char *value, unsigned int valuelen)
|
const char *value, unsigned int valuelen)
|
||||||
{
|
{
|
||||||
char *p;
|
int len, tmp;
|
||||||
int len, total, tmp;
|
|
||||||
|
|
||||||
/* "%u %s=%s\n" */
|
/* "%u %s=%s\n" */
|
||||||
len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
|
len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
|
||||||
for (tmp = len; tmp > 9; tmp /= 10)
|
for (tmp = len; tmp > 9; tmp /= 10)
|
||||||
len++;
|
len++;
|
||||||
|
|
||||||
total = sb->len + len;
|
strbuf_grow(sb, len);
|
||||||
if (total > sb->alloc) {
|
strbuf_addf(sb, "%u %s=", len, keyword);
|
||||||
sb->buf = xrealloc(sb->buf, total);
|
strbuf_add(sb, value, valuelen);
|
||||||
sb->alloc = total;
|
strbuf_addch(sb, '\n');
|
||||||
}
|
|
||||||
|
|
||||||
p = sb->buf;
|
|
||||||
p += sprintf(p, "%u %s=", len, keyword);
|
|
||||||
memcpy(p, value, valuelen);
|
|
||||||
p += valuelen;
|
|
||||||
*p = '\n';
|
|
||||||
sb->len = total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ustar_header_chksum(const struct ustar_header *header)
|
static unsigned int ustar_header_chksum(const struct ustar_header *header)
|
||||||
@ -154,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
|||||||
struct strbuf ext_header;
|
struct strbuf ext_header;
|
||||||
|
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
ext_header.buf = NULL;
|
strbuf_init(&ext_header, 0);
|
||||||
ext_header.len = ext_header.alloc = 0;
|
|
||||||
|
|
||||||
if (!sha1) {
|
if (!sha1) {
|
||||||
*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
|
*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
|
||||||
@ -167,7 +143,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
|||||||
sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
|
sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
|
||||||
} else {
|
} else {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr, "%.*s\n", path->len, path->buf);
|
fprintf(stderr, "%.*s\n", (int)path->len, path->buf);
|
||||||
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
||||||
*header.typeflag = TYPEFLAG_DIR;
|
*header.typeflag = TYPEFLAG_DIR;
|
||||||
mode = (mode | 0777) & ~tar_umask;
|
mode = (mode | 0777) & ~tar_umask;
|
||||||
@ -226,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
|||||||
|
|
||||||
if (ext_header.len > 0) {
|
if (ext_header.len > 0) {
|
||||||
write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
|
write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
|
||||||
free(ext_header.buf);
|
|
||||||
}
|
}
|
||||||
|
strbuf_release(&ext_header);
|
||||||
write_blocked(&header, sizeof(header));
|
write_blocked(&header, sizeof(header));
|
||||||
if (S_ISREG(mode) && buffer && size > 0)
|
if (S_ISREG(mode) && buffer && size > 0)
|
||||||
write_blocked(buffer, size);
|
write_blocked(buffer, size);
|
||||||
@ -236,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
|||||||
static void write_global_extended_header(const unsigned char *sha1)
|
static void write_global_extended_header(const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
struct strbuf ext_header;
|
struct strbuf ext_header;
|
||||||
ext_header.buf = NULL;
|
|
||||||
ext_header.len = ext_header.alloc = 0;
|
strbuf_init(&ext_header, 0);
|
||||||
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
|
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
|
||||||
write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
|
write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
|
||||||
free(ext_header.buf);
|
strbuf_release(&ext_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int git_tar_config(const char *var, const char *value)
|
static int git_tar_config(const char *var, const char *value)
|
||||||
@ -261,28 +237,17 @@ static int write_tar_entry(const unsigned char *sha1,
|
|||||||
const char *base, int baselen,
|
const char *base, int baselen,
|
||||||
const char *filename, unsigned mode, int stage)
|
const char *filename, unsigned mode, int stage)
|
||||||
{
|
{
|
||||||
static struct strbuf path;
|
static struct strbuf path = STRBUF_INIT;
|
||||||
int filenamelen = strlen(filename);
|
|
||||||
void *buffer;
|
void *buffer;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
|
||||||
if (!path.alloc) {
|
strbuf_reset(&path);
|
||||||
path.buf = xmalloc(PATH_MAX);
|
strbuf_grow(&path, PATH_MAX);
|
||||||
path.alloc = PATH_MAX;
|
strbuf_add(&path, base, baselen);
|
||||||
path.len = path.eof = 0;
|
strbuf_addstr(&path, filename);
|
||||||
}
|
|
||||||
if (path.alloc < baselen + filenamelen + 1) {
|
|
||||||
free(path.buf);
|
|
||||||
path.buf = xmalloc(baselen + filenamelen + 1);
|
|
||||||
path.alloc = baselen + filenamelen + 1;
|
|
||||||
}
|
|
||||||
memcpy(path.buf, base, baselen);
|
|
||||||
memcpy(path.buf + baselen, filename, filenamelen);
|
|
||||||
path.len = baselen + filenamelen;
|
|
||||||
path.buf[path.len] = '\0';
|
|
||||||
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
||||||
strbuf_append_string(&path, "/");
|
strbuf_addch(&path, '/');
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
size = 0;
|
size = 0;
|
||||||
} else {
|
} else {
|
||||||
|
7
attr.c
7
attr.c
@ -160,12 +160,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
|
|||||||
else if (!equals)
|
else if (!equals)
|
||||||
e->setto = ATTR__TRUE;
|
e->setto = ATTR__TRUE;
|
||||||
else {
|
else {
|
||||||
char *value;
|
e->setto = xmemdupz(equals + 1, ep - equals - 1);
|
||||||
int vallen = ep - equals;
|
|
||||||
value = xmalloc(vallen);
|
|
||||||
memcpy(value, equals+1, vallen-1);
|
|
||||||
value[vallen-1] = 0;
|
|
||||||
e->setto = value;
|
|
||||||
}
|
}
|
||||||
e->attr = git_attr(cp, len);
|
e->attr = git_attr(cp, len);
|
||||||
}
|
}
|
||||||
|
@ -71,12 +71,8 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
|
|||||||
baselen = common_prefix(pathspec);
|
baselen = common_prefix(pathspec);
|
||||||
path = ".";
|
path = ".";
|
||||||
base = "";
|
base = "";
|
||||||
if (baselen) {
|
if (baselen)
|
||||||
char *common = xmalloc(baselen + 1);
|
path = base = xmemdupz(*pathspec, baselen);
|
||||||
memcpy(common, *pathspec, baselen);
|
|
||||||
common[baselen] = 0;
|
|
||||||
path = base = common;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the directory and prune it */
|
/* Read the directory and prune it */
|
||||||
read_directory(dir, path, base, baselen, pathspec);
|
read_directory(dir, path, base, baselen, pathspec);
|
||||||
|
512
builtin-apply.c
512
builtin-apply.c
@ -41,7 +41,7 @@ static int apply_in_reverse;
|
|||||||
static int apply_with_reject;
|
static int apply_with_reject;
|
||||||
static int apply_verbosely;
|
static int apply_verbosely;
|
||||||
static int no_add;
|
static int no_add;
|
||||||
static int show_index_info;
|
static const char *fake_ancestor;
|
||||||
static int line_termination = '\n';
|
static int line_termination = '\n';
|
||||||
static unsigned long p_context = ULONG_MAX;
|
static unsigned long p_context = ULONG_MAX;
|
||||||
static const char apply_usage[] =
|
static const char apply_usage[] =
|
||||||
@ -163,15 +163,14 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
|
|||||||
fputs(pre, output);
|
fputs(pre, output);
|
||||||
if (patch->old_name && patch->new_name &&
|
if (patch->old_name && patch->new_name &&
|
||||||
strcmp(patch->old_name, patch->new_name)) {
|
strcmp(patch->old_name, patch->new_name)) {
|
||||||
write_name_quoted(NULL, 0, patch->old_name, 1, output);
|
quote_c_style(patch->old_name, NULL, output, 0);
|
||||||
fputs(" => ", output);
|
fputs(" => ", output);
|
||||||
write_name_quoted(NULL, 0, patch->new_name, 1, output);
|
quote_c_style(patch->new_name, NULL, output, 0);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const char *n = patch->new_name;
|
const char *n = patch->new_name;
|
||||||
if (!n)
|
if (!n)
|
||||||
n = patch->old_name;
|
n = patch->old_name;
|
||||||
write_name_quoted(NULL, 0, n, 1, output);
|
quote_c_style(n, NULL, output, 0);
|
||||||
}
|
}
|
||||||
fputs(post, output);
|
fputs(post, output);
|
||||||
}
|
}
|
||||||
@ -179,36 +178,18 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
|
|||||||
#define CHUNKSIZE (8192)
|
#define CHUNKSIZE (8192)
|
||||||
#define SLOP (16)
|
#define SLOP (16)
|
||||||
|
|
||||||
static void *read_patch_file(int fd, unsigned long *sizep)
|
static void read_patch_file(struct strbuf *sb, int fd)
|
||||||
{
|
{
|
||||||
unsigned long size = 0, alloc = CHUNKSIZE;
|
if (strbuf_read(sb, fd, 0) < 0)
|
||||||
void *buffer = xmalloc(alloc);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
ssize_t nr = alloc - size;
|
|
||||||
if (nr < 1024) {
|
|
||||||
alloc += CHUNKSIZE;
|
|
||||||
buffer = xrealloc(buffer, alloc);
|
|
||||||
nr = alloc - size;
|
|
||||||
}
|
|
||||||
nr = xread(fd, (char *) buffer + size, nr);
|
|
||||||
if (!nr)
|
|
||||||
break;
|
|
||||||
if (nr < 0)
|
|
||||||
die("git-apply: read returned %s", strerror(errno));
|
die("git-apply: read returned %s", strerror(errno));
|
||||||
size += nr;
|
|
||||||
}
|
|
||||||
*sizep = size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that we have some slop in the buffer
|
* Make sure that we have some slop in the buffer
|
||||||
* so that we can do speculative "memcmp" etc, and
|
* so that we can do speculative "memcmp" etc, and
|
||||||
* see to it that it is NUL-filled.
|
* see to it that it is NUL-filled.
|
||||||
*/
|
*/
|
||||||
if (alloc < size + SLOP)
|
strbuf_grow(sb, SLOP);
|
||||||
buffer = xrealloc(buffer, size + SLOP);
|
memset(sb->buf + sb->len, 0, SLOP);
|
||||||
memset((char *) buffer + size, 0, SLOP);
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long linelen(const char *buffer, unsigned long size)
|
static unsigned long linelen(const char *buffer, unsigned long size)
|
||||||
@ -244,35 +225,33 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
|
|||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
const char *start = line;
|
const char *start = line;
|
||||||
char *name;
|
|
||||||
|
|
||||||
if (*line == '"') {
|
if (*line == '"') {
|
||||||
|
struct strbuf name;
|
||||||
|
|
||||||
/* Proposed "new-style" GNU patch/diff format; see
|
/* Proposed "new-style" GNU patch/diff format; see
|
||||||
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
|
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
|
||||||
*/
|
*/
|
||||||
name = unquote_c_style(line, NULL);
|
strbuf_init(&name, 0);
|
||||||
if (name) {
|
if (!unquote_c_style(&name, line, NULL)) {
|
||||||
char *cp = name;
|
char *cp;
|
||||||
while (p_value) {
|
|
||||||
|
for (cp = name.buf; p_value; p_value--) {
|
||||||
cp = strchr(cp, '/');
|
cp = strchr(cp, '/');
|
||||||
if (!cp)
|
if (!cp)
|
||||||
break;
|
break;
|
||||||
cp++;
|
cp++;
|
||||||
p_value--;
|
|
||||||
}
|
}
|
||||||
if (cp) {
|
if (cp) {
|
||||||
/* name can later be freed, so we need
|
/* name can later be freed, so we need
|
||||||
* to memmove, not just return cp
|
* to memmove, not just return cp
|
||||||
*/
|
*/
|
||||||
memmove(name, cp, strlen(cp) + 1);
|
strbuf_remove(&name, 0, cp - name.buf);
|
||||||
free(def);
|
free(def);
|
||||||
return name;
|
return strbuf_detach(&name, NULL);
|
||||||
}
|
|
||||||
else {
|
|
||||||
free(name);
|
|
||||||
name = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strbuf_release(&name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -304,13 +283,10 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
|
|||||||
int deflen = strlen(def);
|
int deflen = strlen(def);
|
||||||
if (deflen < len && !strncmp(start, def, deflen))
|
if (deflen < len && !strncmp(start, def, deflen))
|
||||||
return def;
|
return def;
|
||||||
|
free(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
name = xmalloc(len + 1);
|
return xmemdupz(start, len);
|
||||||
memcpy(name, start, len);
|
|
||||||
name[len] = 0;
|
|
||||||
free(def);
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_slashes(const char *cp)
|
static int count_slashes(const char *cp)
|
||||||
@ -583,29 +559,30 @@ static const char *stop_at_slash(const char *line, int llen)
|
|||||||
*/
|
*/
|
||||||
static char *git_header_name(char *line, int llen)
|
static char *git_header_name(char *line, int llen)
|
||||||
{
|
{
|
||||||
int len;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *second = NULL;
|
const char *second = NULL;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
line += strlen("diff --git ");
|
line += strlen("diff --git ");
|
||||||
llen -= strlen("diff --git ");
|
llen -= strlen("diff --git ");
|
||||||
|
|
||||||
if (*line == '"') {
|
if (*line == '"') {
|
||||||
const char *cp;
|
const char *cp;
|
||||||
char *first = unquote_c_style(line, &second);
|
struct strbuf first;
|
||||||
if (!first)
|
struct strbuf sp;
|
||||||
return NULL;
|
|
||||||
|
strbuf_init(&first, 0);
|
||||||
|
strbuf_init(&sp, 0);
|
||||||
|
|
||||||
|
if (unquote_c_style(&first, line, &second))
|
||||||
|
goto free_and_fail1;
|
||||||
|
|
||||||
/* advance to the first slash */
|
/* advance to the first slash */
|
||||||
cp = stop_at_slash(first, strlen(first));
|
cp = stop_at_slash(first.buf, first.len);
|
||||||
if (!cp || cp == first) {
|
|
||||||
/* we do not accept absolute paths */
|
/* we do not accept absolute paths */
|
||||||
free_first_and_fail:
|
if (!cp || cp == first.buf)
|
||||||
free(first);
|
goto free_and_fail1;
|
||||||
return NULL;
|
strbuf_remove(&first, 0, cp + 1 - first.buf);
|
||||||
}
|
|
||||||
len = strlen(cp+1);
|
|
||||||
memmove(first, cp+1, len+1); /* including NUL */
|
|
||||||
|
|
||||||
/* second points at one past closing dq of name.
|
/* second points at one past closing dq of name.
|
||||||
* find the second name.
|
* find the second name.
|
||||||
@ -614,40 +591,40 @@ static char *git_header_name(char *line, int llen)
|
|||||||
second++;
|
second++;
|
||||||
|
|
||||||
if (line + llen <= second)
|
if (line + llen <= second)
|
||||||
goto free_first_and_fail;
|
goto free_and_fail1;
|
||||||
if (*second == '"') {
|
if (*second == '"') {
|
||||||
char *sp = unquote_c_style(second, NULL);
|
if (unquote_c_style(&sp, second, NULL))
|
||||||
if (!sp)
|
goto free_and_fail1;
|
||||||
goto free_first_and_fail;
|
cp = stop_at_slash(sp.buf, sp.len);
|
||||||
cp = stop_at_slash(sp, strlen(sp));
|
if (!cp || cp == sp.buf)
|
||||||
if (!cp || cp == sp) {
|
goto free_and_fail1;
|
||||||
free_both_and_fail:
|
|
||||||
free(sp);
|
|
||||||
goto free_first_and_fail;
|
|
||||||
}
|
|
||||||
/* They must match, otherwise ignore */
|
/* They must match, otherwise ignore */
|
||||||
if (strcmp(cp+1, first))
|
if (strcmp(cp + 1, first.buf))
|
||||||
goto free_both_and_fail;
|
goto free_and_fail1;
|
||||||
free(sp);
|
strbuf_release(&sp);
|
||||||
return first;
|
return strbuf_detach(&first, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unquoted second */
|
/* unquoted second */
|
||||||
cp = stop_at_slash(second, line + llen - second);
|
cp = stop_at_slash(second, line + llen - second);
|
||||||
if (!cp || cp == second)
|
if (!cp || cp == second)
|
||||||
goto free_first_and_fail;
|
goto free_and_fail1;
|
||||||
cp++;
|
cp++;
|
||||||
if (line + llen - cp != len + 1 ||
|
if (line + llen - cp != first.len + 1 ||
|
||||||
memcmp(first, cp, len))
|
memcmp(first.buf, cp, first.len))
|
||||||
goto free_first_and_fail;
|
goto free_and_fail1;
|
||||||
return first;
|
return strbuf_detach(&first, NULL);
|
||||||
|
|
||||||
|
free_and_fail1:
|
||||||
|
strbuf_release(&first);
|
||||||
|
strbuf_release(&sp);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unquoted first name */
|
/* unquoted first name */
|
||||||
name = stop_at_slash(line, llen);
|
name = stop_at_slash(line, llen);
|
||||||
if (!name || name == line)
|
if (!name || name == line)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
name++;
|
name++;
|
||||||
|
|
||||||
/* since the first name is unquoted, a dq if exists must be
|
/* since the first name is unquoted, a dq if exists must be
|
||||||
@ -655,28 +632,30 @@ static char *git_header_name(char *line, int llen)
|
|||||||
*/
|
*/
|
||||||
for (second = name; second < line + llen; second++) {
|
for (second = name; second < line + llen; second++) {
|
||||||
if (*second == '"') {
|
if (*second == '"') {
|
||||||
const char *cp = second;
|
struct strbuf sp;
|
||||||
const char *np;
|
const char *np;
|
||||||
char *sp = unquote_c_style(second, NULL);
|
|
||||||
|
|
||||||
if (!sp)
|
strbuf_init(&sp, 0);
|
||||||
return NULL;
|
if (unquote_c_style(&sp, second, NULL))
|
||||||
np = stop_at_slash(sp, strlen(sp));
|
goto free_and_fail2;
|
||||||
if (!np || np == sp) {
|
|
||||||
free_second_and_fail:
|
np = stop_at_slash(sp.buf, sp.len);
|
||||||
free(sp);
|
if (!np || np == sp.buf)
|
||||||
return NULL;
|
goto free_and_fail2;
|
||||||
}
|
|
||||||
np++;
|
np++;
|
||||||
len = strlen(np);
|
|
||||||
if (len < cp - name &&
|
len = sp.buf + sp.len - np;
|
||||||
|
if (len < second - name &&
|
||||||
!strncmp(np, name, len) &&
|
!strncmp(np, name, len) &&
|
||||||
isspace(name[len])) {
|
isspace(name[len])) {
|
||||||
/* Good */
|
/* Good */
|
||||||
memmove(sp, np, len + 1);
|
strbuf_remove(&sp, 0, np - sp.buf);
|
||||||
return sp;
|
return strbuf_detach(&sp, NULL);
|
||||||
}
|
}
|
||||||
goto free_second_and_fail;
|
|
||||||
|
free_and_fail2:
|
||||||
|
strbuf_release(&sp);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,10 +679,7 @@ static char *git_header_name(char *line, int llen)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (second[len] == '\n' && !memcmp(name, second, len)) {
|
if (second[len] == '\n' && !memcmp(name, second, len)) {
|
||||||
char *ret = xmalloc(len + 1);
|
return xmemdupz(name, len);
|
||||||
memcpy(ret, name, len);
|
|
||||||
ret[len] = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1397,96 +1373,66 @@ static const char minuses[]= "--------------------------------------------------
|
|||||||
|
|
||||||
static void show_stats(struct patch *patch)
|
static void show_stats(struct patch *patch)
|
||||||
{
|
{
|
||||||
const char *prefix = "";
|
struct strbuf qname;
|
||||||
char *name = patch->new_name;
|
char *cp = patch->new_name ? patch->new_name : patch->old_name;
|
||||||
char *qname = NULL;
|
int max, add, del;
|
||||||
int len, max, add, del, total;
|
|
||||||
|
|
||||||
if (!name)
|
strbuf_init(&qname, 0);
|
||||||
name = patch->old_name;
|
quote_c_style(cp, &qname, NULL, 0);
|
||||||
|
|
||||||
if (0 < (len = quote_c_style(name, NULL, NULL, 0))) {
|
|
||||||
qname = xmalloc(len + 1);
|
|
||||||
quote_c_style(name, qname, NULL, 0);
|
|
||||||
name = qname;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "scale" the filename
|
* "scale" the filename
|
||||||
*/
|
*/
|
||||||
len = strlen(name);
|
|
||||||
max = max_len;
|
max = max_len;
|
||||||
if (max > 50)
|
if (max > 50)
|
||||||
max = 50;
|
max = 50;
|
||||||
if (len > max) {
|
|
||||||
char *slash;
|
if (qname.len > max) {
|
||||||
prefix = "...";
|
cp = strchr(qname.buf + qname.len + 3 - max, '/');
|
||||||
max -= 3;
|
if (!cp)
|
||||||
name += len - max;
|
cp = qname.buf + qname.len + 3 - max;
|
||||||
slash = strchr(name, '/');
|
strbuf_splice(&qname, 0, cp - qname.buf, "...", 3);
|
||||||
if (slash)
|
|
||||||
name = slash;
|
|
||||||
}
|
}
|
||||||
len = max;
|
|
||||||
|
if (patch->is_binary) {
|
||||||
|
printf(" %-*s | Bin\n", max, qname.buf);
|
||||||
|
strbuf_release(&qname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" %-*s |", max, qname.buf);
|
||||||
|
strbuf_release(&qname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scale the add/delete
|
* scale the add/delete
|
||||||
*/
|
*/
|
||||||
max = max_change;
|
max = max + max_change > 70 ? 70 - max : max_change;
|
||||||
if (max + len > 70)
|
|
||||||
max = 70 - len;
|
|
||||||
|
|
||||||
add = patch->lines_added;
|
add = patch->lines_added;
|
||||||
del = patch->lines_deleted;
|
del = patch->lines_deleted;
|
||||||
total = add + del;
|
|
||||||
|
|
||||||
if (max_change > 0) {
|
if (max_change > 0) {
|
||||||
total = (total * max + max_change / 2) / max_change;
|
int total = ((add + del) * max + max_change / 2) / max_change;
|
||||||
add = (add * max + max_change / 2) / max_change;
|
add = (add * max + max_change / 2) / max_change;
|
||||||
del = total - add;
|
del = total - add;
|
||||||
}
|
}
|
||||||
if (patch->is_binary)
|
printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
|
||||||
printf(" %s%-*s | Bin\n", prefix, len, name);
|
|
||||||
else
|
|
||||||
printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
|
|
||||||
len, name, patch->lines_added + patch->lines_deleted,
|
|
||||||
add, pluses, del, minuses);
|
add, pluses, del, minuses);
|
||||||
free(qname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
|
static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
unsigned long got;
|
|
||||||
unsigned long nsize;
|
|
||||||
char *nbuf;
|
|
||||||
unsigned long size = *size_p;
|
|
||||||
char *buf = *buf_p;
|
|
||||||
|
|
||||||
switch (st->st_mode & S_IFMT) {
|
switch (st->st_mode & S_IFMT) {
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
return readlink(path, buf, size) != size;
|
strbuf_grow(buf, st->st_size);
|
||||||
|
if (readlink(path, buf->buf, st->st_size) != st->st_size)
|
||||||
|
return -1;
|
||||||
|
strbuf_setlen(buf, st->st_size);
|
||||||
|
return 0;
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
fd = open(path, O_RDONLY);
|
if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
|
||||||
if (fd < 0)
|
return error("unable to open or read %s", path);
|
||||||
return error("unable to open %s", path);
|
convert_to_git(path, buf->buf, buf->len, buf);
|
||||||
got = 0;
|
return 0;
|
||||||
for (;;) {
|
|
||||||
ssize_t ret = xread(fd, buf + got, size - got);
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
got += ret;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
nsize = got;
|
|
||||||
nbuf = convert_to_git(path, buf, &nsize);
|
|
||||||
if (nbuf) {
|
|
||||||
free(buf);
|
|
||||||
*buf_p = nbuf;
|
|
||||||
*alloc_p = nsize;
|
|
||||||
*size_p = nsize;
|
|
||||||
}
|
|
||||||
return got != size;
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1591,12 +1537,6 @@ static void remove_last_line(const char **rbuf, int *rsize)
|
|||||||
*rsize = offset + 1;
|
*rsize = offset + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct buffer_desc {
|
|
||||||
char *buffer;
|
|
||||||
unsigned long size;
|
|
||||||
unsigned long alloc;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int apply_line(char *output, const char *patch, int plen)
|
static int apply_line(char *output, const char *patch, int plen)
|
||||||
{
|
{
|
||||||
/* plen is number of bytes to be copied from patch,
|
/* plen is number of bytes to be copied from patch,
|
||||||
@ -1673,10 +1613,9 @@ static int apply_line(char *output, const char *patch, int plen)
|
|||||||
return output + plen - buf;
|
return output + plen - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
|
static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int inaccurate_eof)
|
||||||
{
|
{
|
||||||
int match_beginning, match_end;
|
int match_beginning, match_end;
|
||||||
char *buf = desc->buffer;
|
|
||||||
const char *patch = frag->patch;
|
const char *patch = frag->patch;
|
||||||
int offset, size = frag->size;
|
int offset, size = frag->size;
|
||||||
char *old = xmalloc(size);
|
char *old = xmalloc(size);
|
||||||
@ -1787,24 +1726,17 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
|||||||
lines = 0;
|
lines = 0;
|
||||||
pos = frag->newpos;
|
pos = frag->newpos;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
offset = find_offset(buf, desc->size,
|
offset = find_offset(buf->buf, buf->len,
|
||||||
oldlines, oldsize, pos, &lines);
|
oldlines, oldsize, pos, &lines);
|
||||||
if (match_end && offset + oldsize != desc->size)
|
if (match_end && offset + oldsize != buf->len)
|
||||||
offset = -1;
|
offset = -1;
|
||||||
if (match_beginning && offset)
|
if (match_beginning && offset)
|
||||||
offset = -1;
|
offset = -1;
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
int diff;
|
|
||||||
unsigned long size, alloc;
|
|
||||||
|
|
||||||
if (new_whitespace == strip_whitespace &&
|
if (new_whitespace == strip_whitespace &&
|
||||||
(desc->size - oldsize - offset == 0)) /* end of file? */
|
(buf->len - oldsize - offset == 0)) /* end of file? */
|
||||||
newsize -= new_blank_lines_at_end;
|
newsize -= new_blank_lines_at_end;
|
||||||
|
|
||||||
diff = newsize - oldsize;
|
|
||||||
size = desc->size + diff;
|
|
||||||
alloc = desc->alloc;
|
|
||||||
|
|
||||||
/* Warn if it was necessary to reduce the number
|
/* Warn if it was necessary to reduce the number
|
||||||
* of context lines.
|
* of context lines.
|
||||||
*/
|
*/
|
||||||
@ -1814,19 +1746,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
|||||||
" to apply fragment at %d\n",
|
" to apply fragment at %d\n",
|
||||||
leading, trailing, pos + lines);
|
leading, trailing, pos + lines);
|
||||||
|
|
||||||
if (size > alloc) {
|
strbuf_splice(buf, offset, oldsize, newlines, newsize);
|
||||||
alloc = size + 8192;
|
|
||||||
desc->alloc = alloc;
|
|
||||||
buf = xrealloc(buf, alloc);
|
|
||||||
desc->buffer = buf;
|
|
||||||
}
|
|
||||||
desc->size = size;
|
|
||||||
memmove(buf + offset + newsize,
|
|
||||||
buf + offset + oldsize,
|
|
||||||
size - offset - newsize);
|
|
||||||
memcpy(buf + offset, newlines, newsize);
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1862,12 +1783,11 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
|
static int apply_binary_fragment(struct strbuf *buf, struct patch *patch)
|
||||||
{
|
{
|
||||||
unsigned long dst_size;
|
|
||||||
struct fragment *fragment = patch->fragments;
|
struct fragment *fragment = patch->fragments;
|
||||||
void *data;
|
unsigned long len;
|
||||||
void *result;
|
void *dst;
|
||||||
|
|
||||||
/* Binary patch is irreversible without the optional second hunk */
|
/* Binary patch is irreversible without the optional second hunk */
|
||||||
if (apply_in_reverse) {
|
if (apply_in_reverse) {
|
||||||
@ -1878,29 +1798,24 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
|
|||||||
? patch->new_name : patch->old_name);
|
? patch->new_name : patch->old_name);
|
||||||
fragment = fragment->next;
|
fragment = fragment->next;
|
||||||
}
|
}
|
||||||
data = (void*) fragment->patch;
|
|
||||||
switch (fragment->binary_patch_method) {
|
switch (fragment->binary_patch_method) {
|
||||||
case BINARY_DELTA_DEFLATED:
|
case BINARY_DELTA_DEFLATED:
|
||||||
result = patch_delta(desc->buffer, desc->size,
|
dst = patch_delta(buf->buf, buf->len, fragment->patch,
|
||||||
data,
|
fragment->size, &len);
|
||||||
fragment->size,
|
if (!dst)
|
||||||
&dst_size);
|
|
||||||
free(desc->buffer);
|
|
||||||
desc->buffer = result;
|
|
||||||
break;
|
|
||||||
case BINARY_LITERAL_DEFLATED:
|
|
||||||
free(desc->buffer);
|
|
||||||
desc->buffer = data;
|
|
||||||
dst_size = fragment->size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!desc->buffer)
|
|
||||||
return -1;
|
return -1;
|
||||||
desc->size = desc->alloc = dst_size;
|
/* XXX patch_delta NUL-terminates */
|
||||||
|
strbuf_attach(buf, dst, len, len + 1);
|
||||||
return 0;
|
return 0;
|
||||||
|
case BINARY_LITERAL_DEFLATED:
|
||||||
|
strbuf_reset(buf);
|
||||||
|
strbuf_add(buf, fragment->patch, fragment->size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
static int apply_binary(struct strbuf *buf, struct patch *patch)
|
||||||
{
|
{
|
||||||
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
@ -1919,7 +1834,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
|||||||
/* See if the old one matches what the patch
|
/* See if the old one matches what the patch
|
||||||
* applies to.
|
* applies to.
|
||||||
*/
|
*/
|
||||||
hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
|
hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
|
||||||
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
|
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
|
||||||
return error("the patch applies to '%s' (%s), "
|
return error("the patch applies to '%s' (%s), "
|
||||||
"which does not match the "
|
"which does not match the "
|
||||||
@ -1928,16 +1843,14 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Otherwise, the old one must be empty. */
|
/* Otherwise, the old one must be empty. */
|
||||||
if (desc->size)
|
if (buf->len)
|
||||||
return error("the patch applies to an empty "
|
return error("the patch applies to an empty "
|
||||||
"'%s' but it is not empty", name);
|
"'%s' but it is not empty", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
get_sha1_hex(patch->new_sha1_prefix, sha1);
|
get_sha1_hex(patch->new_sha1_prefix, sha1);
|
||||||
if (is_null_sha1(sha1)) {
|
if (is_null_sha1(sha1)) {
|
||||||
free(desc->buffer);
|
strbuf_release(buf);
|
||||||
desc->alloc = desc->size = 0;
|
|
||||||
desc->buffer = NULL;
|
|
||||||
return 0; /* deletion patch */
|
return 0; /* deletion patch */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1945,43 +1858,44 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
|||||||
/* We already have the postimage */
|
/* We already have the postimage */
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
char *result;
|
||||||
|
|
||||||
free(desc->buffer);
|
result = read_sha1_file(sha1, &type, &size);
|
||||||
desc->buffer = read_sha1_file(sha1, &type, &size);
|
if (!result)
|
||||||
if (!desc->buffer)
|
|
||||||
return error("the necessary postimage %s for "
|
return error("the necessary postimage %s for "
|
||||||
"'%s' cannot be read",
|
"'%s' cannot be read",
|
||||||
patch->new_sha1_prefix, name);
|
patch->new_sha1_prefix, name);
|
||||||
desc->alloc = desc->size = size;
|
/* XXX read_sha1_file NUL-terminates */
|
||||||
}
|
strbuf_attach(buf, result, size, size + 1);
|
||||||
else {
|
} else {
|
||||||
/* We have verified desc matches the preimage;
|
/* We have verified buf matches the preimage;
|
||||||
* apply the patch data to it, which is stored
|
* apply the patch data to it, which is stored
|
||||||
* in the patch->fragments->{patch,size}.
|
* in the patch->fragments->{patch,size}.
|
||||||
*/
|
*/
|
||||||
if (apply_binary_fragment(desc, patch))
|
if (apply_binary_fragment(buf, patch))
|
||||||
return error("binary patch does not apply to '%s'",
|
return error("binary patch does not apply to '%s'",
|
||||||
name);
|
name);
|
||||||
|
|
||||||
/* verify that the result matches */
|
/* verify that the result matches */
|
||||||
hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
|
hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
|
||||||
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
|
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
|
||||||
return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1));
|
return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
|
||||||
|
name, patch->new_sha1_prefix, sha1_to_hex(sha1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
static int apply_fragments(struct strbuf *buf, struct patch *patch)
|
||||||
{
|
{
|
||||||
struct fragment *frag = patch->fragments;
|
struct fragment *frag = patch->fragments;
|
||||||
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
||||||
|
|
||||||
if (patch->is_binary)
|
if (patch->is_binary)
|
||||||
return apply_binary(desc, patch);
|
return apply_binary(buf, patch);
|
||||||
|
|
||||||
while (frag) {
|
while (frag) {
|
||||||
if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) {
|
if (apply_one_fragment(buf, frag, patch->inaccurate_eof)) {
|
||||||
error("patch failed: %s:%ld", name, frag->oldpos);
|
error("patch failed: %s:%ld", name, frag->oldpos);
|
||||||
if (!apply_with_reject)
|
if (!apply_with_reject)
|
||||||
return -1;
|
return -1;
|
||||||
@ -1992,76 +1906,56 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p,
|
static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
|
||||||
unsigned long *size_p)
|
|
||||||
{
|
{
|
||||||
if (!ce)
|
if (!ce)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||||
*buf_p = xmalloc(100);
|
strbuf_grow(buf, 100);
|
||||||
*size_p = snprintf(*buf_p, 100,
|
strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
|
||||||
"Subproject commit %s\n", sha1_to_hex(ce->sha1));
|
|
||||||
} else {
|
} else {
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
*buf_p = read_sha1_file(ce->sha1, &type, size_p);
|
unsigned long sz;
|
||||||
if (!*buf_p)
|
char *result;
|
||||||
|
|
||||||
|
result = read_sha1_file(ce->sha1, &type, &sz);
|
||||||
|
if (!result)
|
||||||
return -1;
|
return -1;
|
||||||
|
/* XXX read_sha1_file NUL-terminates */
|
||||||
|
strbuf_attach(buf, result, sz, sz + 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
|
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
|
||||||
{
|
{
|
||||||
char *buf;
|
struct strbuf buf;
|
||||||
unsigned long size, alloc;
|
|
||||||
struct buffer_desc desc;
|
|
||||||
|
|
||||||
size = 0;
|
strbuf_init(&buf, 0);
|
||||||
alloc = 0;
|
|
||||||
buf = NULL;
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
if (read_file_or_gitlink(ce, &buf, &size))
|
if (read_file_or_gitlink(ce, &buf))
|
||||||
return error("read of %s failed", patch->old_name);
|
return error("read of %s failed", patch->old_name);
|
||||||
alloc = size;
|
|
||||||
} else if (patch->old_name) {
|
} else if (patch->old_name) {
|
||||||
if (S_ISGITLINK(patch->old_mode)) {
|
if (S_ISGITLINK(patch->old_mode)) {
|
||||||
if (ce)
|
if (ce) {
|
||||||
read_file_or_gitlink(ce, &buf, &size);
|
read_file_or_gitlink(ce, &buf);
|
||||||
else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* There is no way to apply subproject
|
* There is no way to apply subproject
|
||||||
* patch without looking at the index.
|
* patch without looking at the index.
|
||||||
*/
|
*/
|
||||||
patch->fragments = NULL;
|
patch->fragments = NULL;
|
||||||
size = 0;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (read_old_data(st, patch->old_name, &buf))
|
||||||
size = xsize_t(st->st_size);
|
return error("read of %s failed", patch->old_name);
|
||||||
alloc = size + 8192;
|
|
||||||
buf = xmalloc(alloc);
|
|
||||||
if (read_old_data(st, patch->old_name,
|
|
||||||
&buf, &alloc, &size))
|
|
||||||
return error("read of %s failed",
|
|
||||||
patch->old_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
desc.size = size;
|
if (apply_fragments(&buf, patch) < 0)
|
||||||
desc.alloc = alloc;
|
|
||||||
desc.buffer = buf;
|
|
||||||
|
|
||||||
if (apply_fragments(&desc, patch) < 0)
|
|
||||||
return -1; /* note with --reject this succeeds. */
|
return -1; /* note with --reject this succeeds. */
|
||||||
|
patch->result = strbuf_detach(&buf, &patch->resultsize);
|
||||||
/* NUL terminate the result */
|
|
||||||
if (desc.alloc <= desc.size)
|
|
||||||
desc.buffer = xrealloc(desc.buffer, desc.size + 1);
|
|
||||||
desc.buffer[desc.size] = 0;
|
|
||||||
|
|
||||||
patch->result = desc.buffer;
|
|
||||||
patch->resultsize = desc.size;
|
|
||||||
|
|
||||||
if (0 < patch->is_delete && patch->resultsize)
|
if (0 < patch->is_delete && patch->resultsize)
|
||||||
return error("removal patch leaves file contents");
|
return error("removal patch leaves file contents");
|
||||||
@ -2248,9 +2142,12 @@ static int get_current_sha1(const char *path, unsigned char *sha1)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_index_list(struct patch *list)
|
/* Build an index that contains the just the files needed for a 3way merge */
|
||||||
|
static void build_fake_ancestor(struct patch *list, const char *filename)
|
||||||
{
|
{
|
||||||
struct patch *patch;
|
struct patch *patch;
|
||||||
|
struct index_state result = { 0 };
|
||||||
|
int fd;
|
||||||
|
|
||||||
/* Once we start supporting the reverse patch, it may be
|
/* Once we start supporting the reverse patch, it may be
|
||||||
* worth showing the new sha1 prefix, but until then...
|
* worth showing the new sha1 prefix, but until then...
|
||||||
@ -2258,11 +2155,12 @@ static void show_index_list(struct patch *list)
|
|||||||
for (patch = list; patch; patch = patch->next) {
|
for (patch = list; patch; patch = patch->next) {
|
||||||
const unsigned char *sha1_ptr;
|
const unsigned char *sha1_ptr;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
struct cache_entry *ce;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
name = patch->old_name ? patch->old_name : patch->new_name;
|
name = patch->old_name ? patch->old_name : patch->new_name;
|
||||||
if (0 < patch->is_new)
|
if (0 < patch->is_new)
|
||||||
sha1_ptr = null_sha1;
|
continue;
|
||||||
else if (get_sha1(patch->old_sha1_prefix, sha1))
|
else if (get_sha1(patch->old_sha1_prefix, sha1))
|
||||||
/* git diff has no index line for mode/type changes */
|
/* git diff has no index line for mode/type changes */
|
||||||
if (!patch->lines_added && !patch->lines_deleted) {
|
if (!patch->lines_added && !patch->lines_deleted) {
|
||||||
@ -2277,13 +2175,16 @@ static void show_index_list(struct patch *list)
|
|||||||
else
|
else
|
||||||
sha1_ptr = sha1;
|
sha1_ptr = sha1;
|
||||||
|
|
||||||
printf("%06o %s ",patch->old_mode, sha1_to_hex(sha1_ptr));
|
ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
|
||||||
if (line_termination && quote_c_style(name, NULL, NULL, 0))
|
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
|
||||||
quote_c_style(name, NULL, stdout, 0);
|
die ("Could not add %s to temporary index", name);
|
||||||
else
|
|
||||||
fputs(name, stdout);
|
|
||||||
putchar(line_termination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fd = open(filename, O_WRONLY | O_CREAT, 0666);
|
||||||
|
if (fd < 0 || write_index(&result, fd) || close(fd))
|
||||||
|
die ("Could not write temporary index to %s", filename);
|
||||||
|
|
||||||
|
discard_index(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stat_patch_list(struct patch *patch)
|
static void stat_patch_list(struct patch *patch)
|
||||||
@ -2308,13 +2209,8 @@ static void numstat_patch_list(struct patch *patch)
|
|||||||
if (patch->is_binary)
|
if (patch->is_binary)
|
||||||
printf("-\t-\t");
|
printf("-\t-\t");
|
||||||
else
|
else
|
||||||
printf("%d\t%d\t",
|
printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
|
||||||
patch->lines_added, patch->lines_deleted);
|
write_name_quoted(name, stdout, line_termination);
|
||||||
if (line_termination && quote_c_style(name, NULL, NULL, 0))
|
|
||||||
quote_c_style(name, NULL, stdout, 0);
|
|
||||||
else
|
|
||||||
fputs(name, stdout);
|
|
||||||
putchar(line_termination);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2479,7 +2375,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
|
|||||||
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
|
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char *nbuf;
|
struct strbuf nbuf;
|
||||||
|
|
||||||
if (S_ISGITLINK(mode)) {
|
if (S_ISGITLINK(mode)) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -2498,23 +2394,16 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
nbuf = convert_to_working_tree(path, buf, &size);
|
strbuf_init(&nbuf, 0);
|
||||||
if (nbuf)
|
if (convert_to_working_tree(path, buf, size, &nbuf)) {
|
||||||
buf = nbuf;
|
size = nbuf.len;
|
||||||
|
buf = nbuf.buf;
|
||||||
while (size) {
|
|
||||||
int written = xwrite(fd, buf, size);
|
|
||||||
if (written < 0)
|
|
||||||
die("writing file %s: %s", path, strerror(errno));
|
|
||||||
if (!written)
|
|
||||||
die("out of space writing file %s", path);
|
|
||||||
buf += written;
|
|
||||||
size -= written;
|
|
||||||
}
|
}
|
||||||
|
write_or_die(fd, buf, size);
|
||||||
|
strbuf_release(&nbuf);
|
||||||
|
|
||||||
if (close(fd) < 0)
|
if (close(fd) < 0)
|
||||||
die("closing file %s: %s", path, strerror(errno));
|
die("closing file %s: %s", path, strerror(errno));
|
||||||
if (nbuf)
|
|
||||||
free(nbuf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2747,22 +2636,22 @@ static void prefix_patches(struct patch *p)
|
|||||||
|
|
||||||
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||||
{
|
{
|
||||||
unsigned long offset, size;
|
size_t offset;
|
||||||
char *buffer = read_patch_file(fd, &size);
|
struct strbuf buf;
|
||||||
struct patch *list = NULL, **listp = &list;
|
struct patch *list = NULL, **listp = &list;
|
||||||
int skipped_patch = 0;
|
int skipped_patch = 0;
|
||||||
|
|
||||||
|
strbuf_init(&buf, 0);
|
||||||
patch_input_file = filename;
|
patch_input_file = filename;
|
||||||
if (!buffer)
|
read_patch_file(&buf, fd);
|
||||||
return -1;
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
while (size > 0) {
|
while (offset < buf.len) {
|
||||||
struct patch *patch;
|
struct patch *patch;
|
||||||
int nr;
|
int nr;
|
||||||
|
|
||||||
patch = xcalloc(1, sizeof(*patch));
|
patch = xcalloc(1, sizeof(*patch));
|
||||||
patch->inaccurate_eof = inaccurate_eof;
|
patch->inaccurate_eof = inaccurate_eof;
|
||||||
nr = parse_chunk(buffer + offset, size, patch);
|
nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
|
||||||
if (nr < 0)
|
if (nr < 0)
|
||||||
break;
|
break;
|
||||||
if (apply_in_reverse)
|
if (apply_in_reverse)
|
||||||
@ -2780,7 +2669,6 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
|||||||
skipped_patch++;
|
skipped_patch++;
|
||||||
}
|
}
|
||||||
offset += nr;
|
offset += nr;
|
||||||
size -= nr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whitespace_error && (new_whitespace == error_on_whitespace))
|
if (whitespace_error && (new_whitespace == error_on_whitespace))
|
||||||
@ -2803,8 +2691,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
|||||||
if (apply && write_out_results(list, skipped_patch))
|
if (apply && write_out_results(list, skipped_patch))
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
if (show_index_info)
|
if (fake_ancestor)
|
||||||
show_index_list(list);
|
build_fake_ancestor(list, fake_ancestor);
|
||||||
|
|
||||||
if (diffstat)
|
if (diffstat)
|
||||||
stat_patch_list(list);
|
stat_patch_list(list);
|
||||||
@ -2815,7 +2703,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
|||||||
if (summary)
|
if (summary)
|
||||||
summary_patch_list(list);
|
summary_patch_list(list);
|
||||||
|
|
||||||
free(buffer);
|
strbuf_release(&buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2912,9 +2800,11 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
|||||||
apply = 1;
|
apply = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--index-info")) {
|
if (!strcmp(arg, "--build-fake-ancestor")) {
|
||||||
apply = 0;
|
apply = 0;
|
||||||
show_index_info = 1;
|
if (++i >= argc)
|
||||||
|
die ("need a filename");
|
||||||
|
fake_ancestor = argv[i];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "-z")) {
|
if (!strcmp(arg, "-z")) {
|
||||||
|
@ -81,95 +81,79 @@ static int run_remote_archiver(const char *remote, int argc,
|
|||||||
return !!rv;
|
return !!rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *format_subst(const struct commit *commit, const char *format,
|
static void format_subst(const struct commit *commit,
|
||||||
unsigned long *sizep)
|
const char *src, size_t len,
|
||||||
|
struct strbuf *buf)
|
||||||
{
|
{
|
||||||
unsigned long len = *sizep, result_len = 0;
|
char *to_free = NULL;
|
||||||
const char *a = format;
|
struct strbuf fmt;
|
||||||
char *result = NULL;
|
|
||||||
|
|
||||||
|
if (src == buf->buf)
|
||||||
|
to_free = strbuf_detach(buf, NULL);
|
||||||
|
strbuf_init(&fmt, 0);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *b, *c;
|
const char *b, *c;
|
||||||
char *fmt, *formatted = NULL;
|
|
||||||
unsigned long a_len, fmt_len, formatted_len, allocated = 0;
|
|
||||||
|
|
||||||
b = memmem(a, len, "$Format:", 8);
|
b = memmem(src, len, "$Format:", 8);
|
||||||
if (!b || a + len < b + 9)
|
if (!b || src + len < b + 9)
|
||||||
break;
|
break;
|
||||||
c = memchr(b + 8, '$', len - 8);
|
c = memchr(b + 8, '$', len - 8);
|
||||||
if (!c)
|
if (!c)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
a_len = b - a;
|
strbuf_reset(&fmt);
|
||||||
fmt_len = c - b - 8;
|
strbuf_add(&fmt, b + 8, c - b - 8);
|
||||||
fmt = xmalloc(fmt_len + 1);
|
|
||||||
memcpy(fmt, b + 8, fmt_len);
|
|
||||||
fmt[fmt_len] = '\0';
|
|
||||||
|
|
||||||
formatted_len = format_commit_message(commit, fmt, &formatted,
|
strbuf_add(buf, src, b - src);
|
||||||
&allocated);
|
format_commit_message(commit, fmt.buf, buf);
|
||||||
free(fmt);
|
len -= c + 1 - src;
|
||||||
result = xrealloc(result, result_len + a_len + formatted_len);
|
src = c + 1;
|
||||||
memcpy(result + result_len, a, a_len);
|
|
||||||
memcpy(result + result_len + a_len, formatted, formatted_len);
|
|
||||||
result_len += a_len + formatted_len;
|
|
||||||
len -= c + 1 - a;
|
|
||||||
a = c + 1;
|
|
||||||
}
|
}
|
||||||
|
strbuf_add(buf, src, len);
|
||||||
if (result && len) {
|
strbuf_release(&fmt);
|
||||||
result = xrealloc(result, result_len + len);
|
free(to_free);
|
||||||
memcpy(result + result_len, a, len);
|
|
||||||
result_len += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
*sizep = result_len;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *convert_to_archive(const char *path,
|
static int convert_to_archive(const char *path,
|
||||||
const void *src, unsigned long *sizep,
|
const void *src, size_t len,
|
||||||
|
struct strbuf *buf,
|
||||||
const struct commit *commit)
|
const struct commit *commit)
|
||||||
{
|
{
|
||||||
static struct git_attr *attr_export_subst;
|
static struct git_attr *attr_export_subst;
|
||||||
struct git_attr_check check[1];
|
struct git_attr_check check[1];
|
||||||
|
|
||||||
if (!commit)
|
if (!commit)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
if (!attr_export_subst)
|
if (!attr_export_subst)
|
||||||
attr_export_subst = git_attr("export-subst", 12);
|
attr_export_subst = git_attr("export-subst", 12);
|
||||||
|
|
||||||
check[0].attr = attr_export_subst;
|
check[0].attr = attr_export_subst;
|
||||||
if (git_checkattr(path, ARRAY_SIZE(check), check))
|
if (git_checkattr(path, ARRAY_SIZE(check), check))
|
||||||
return NULL;
|
return 0;
|
||||||
if (!ATTR_TRUE(check[0].value))
|
if (!ATTR_TRUE(check[0].value))
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
return format_subst(commit, src, sizep);
|
format_subst(commit, src, len, buf);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
|
void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
|
||||||
unsigned int mode, enum object_type *type,
|
unsigned int mode, enum object_type *type,
|
||||||
unsigned long *size,
|
unsigned long *sizep,
|
||||||
const struct commit *commit)
|
const struct commit *commit)
|
||||||
{
|
{
|
||||||
void *buffer, *converted;
|
void *buffer;
|
||||||
|
|
||||||
buffer = read_sha1_file(sha1, type, size);
|
buffer = read_sha1_file(sha1, type, sizep);
|
||||||
if (buffer && S_ISREG(mode)) {
|
if (buffer && S_ISREG(mode)) {
|
||||||
converted = convert_to_working_tree(path, buffer, size);
|
struct strbuf buf;
|
||||||
if (converted) {
|
|
||||||
free(buffer);
|
|
||||||
buffer = converted;
|
|
||||||
}
|
|
||||||
|
|
||||||
converted = convert_to_archive(path, buffer, size, commit);
|
strbuf_init(&buf, 0);
|
||||||
if (converted) {
|
strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
|
||||||
free(buffer);
|
convert_to_working_tree(path, buf.buf, buf.len, &buf);
|
||||||
buffer = converted;
|
convert_to_archive(path, buf.buf, buf.len, &buf, commit);
|
||||||
}
|
buffer = strbuf_detach(&buf, sizep);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -1430,8 +1430,7 @@ static void get_commit_info(struct commit *commit,
|
|||||||
static void write_filename_info(const char *path)
|
static void write_filename_info(const char *path)
|
||||||
{
|
{
|
||||||
printf("filename ");
|
printf("filename ");
|
||||||
write_name_quoted(NULL, 0, path, 1, stdout);
|
write_name_quoted(path, stdout, '\n');
|
||||||
putchar('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2001,11 +2000,9 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
|
|||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
struct origin *origin;
|
struct origin *origin;
|
||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
char *buf;
|
struct strbuf buf;
|
||||||
const char *ident;
|
const char *ident;
|
||||||
int fd;
|
|
||||||
time_t now;
|
time_t now;
|
||||||
unsigned long fin_size;
|
|
||||||
int size, len;
|
int size, len;
|
||||||
struct cache_entry *ce;
|
struct cache_entry *ce;
|
||||||
unsigned mode;
|
unsigned mode;
|
||||||
@ -2023,9 +2020,11 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
|
|||||||
|
|
||||||
origin = make_origin(commit, path);
|
origin = make_origin(commit, path);
|
||||||
|
|
||||||
|
strbuf_init(&buf, 0);
|
||||||
if (!contents_from || strcmp("-", contents_from)) {
|
if (!contents_from || strcmp("-", contents_from)) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
const char *read_from;
|
const char *read_from;
|
||||||
|
unsigned long fin_size;
|
||||||
|
|
||||||
if (contents_from) {
|
if (contents_from) {
|
||||||
if (stat(contents_from, &st) < 0)
|
if (stat(contents_from, &st) < 0)
|
||||||
@ -2038,19 +2037,16 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
|
|||||||
read_from = path;
|
read_from = path;
|
||||||
}
|
}
|
||||||
fin_size = xsize_t(st.st_size);
|
fin_size = xsize_t(st.st_size);
|
||||||
buf = xmalloc(fin_size+1);
|
|
||||||
mode = canon_mode(st.st_mode);
|
mode = canon_mode(st.st_mode);
|
||||||
switch (st.st_mode & S_IFMT) {
|
switch (st.st_mode & S_IFMT) {
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
fd = open(read_from, O_RDONLY);
|
if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
|
||||||
if (fd < 0)
|
die("cannot open or read %s", read_from);
|
||||||
die("cannot open %s", read_from);
|
|
||||||
if (read_in_full(fd, buf, fin_size) != fin_size)
|
|
||||||
die("cannot read %s", read_from);
|
|
||||||
break;
|
break;
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
if (readlink(read_from, buf, fin_size+1) != fin_size)
|
if (readlink(read_from, buf.buf, buf.alloc) != fin_size)
|
||||||
die("cannot readlink %s", read_from);
|
die("cannot readlink %s", read_from);
|
||||||
|
buf.len = fin_size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
die("unsupported file type %s", read_from);
|
die("unsupported file type %s", read_from);
|
||||||
@ -2059,26 +2055,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
|
|||||||
else {
|
else {
|
||||||
/* Reading from stdin */
|
/* Reading from stdin */
|
||||||
contents_from = "standard input";
|
contents_from = "standard input";
|
||||||
buf = NULL;
|
|
||||||
fin_size = 0;
|
|
||||||
mode = 0;
|
mode = 0;
|
||||||
while (1) {
|
if (strbuf_read(&buf, 0, 0) < 0)
|
||||||
ssize_t cnt = 8192;
|
die("read error %s from stdin", strerror(errno));
|
||||||
buf = xrealloc(buf, fin_size + cnt);
|
|
||||||
cnt = xread(0, buf + fin_size, cnt);
|
|
||||||
if (cnt < 0)
|
|
||||||
die("read error %s from stdin",
|
|
||||||
strerror(errno));
|
|
||||||
if (!cnt)
|
|
||||||
break;
|
|
||||||
fin_size += cnt;
|
|
||||||
}
|
}
|
||||||
buf = xrealloc(buf, fin_size + 1);
|
origin->file.ptr = buf.buf;
|
||||||
}
|
origin->file.size = buf.len;
|
||||||
buf[fin_size] = 0;
|
pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
|
||||||
origin->file.ptr = buf;
|
|
||||||
origin->file.size = fin_size;
|
|
||||||
pretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);
|
|
||||||
commit->util = origin;
|
commit->util = origin;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -268,23 +268,22 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
char *subject = NULL;
|
struct strbuf subject;
|
||||||
unsigned long subject_len = 0;
|
|
||||||
const char *sub = " **** invalid ref ****";
|
const char *sub = " **** invalid ref ****";
|
||||||
|
|
||||||
|
strbuf_init(&subject, 0);
|
||||||
|
|
||||||
commit = lookup_commit(item->sha1);
|
commit = lookup_commit(item->sha1);
|
||||||
if (commit && !parse_commit(commit)) {
|
if (commit && !parse_commit(commit)) {
|
||||||
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
|
pretty_print_commit(CMIT_FMT_ONELINE, commit,
|
||||||
&subject, &subject_len, 0,
|
&subject, 0, NULL, NULL, 0);
|
||||||
NULL, NULL, 0);
|
sub = subject.buf;
|
||||||
sub = subject;
|
|
||||||
}
|
}
|
||||||
printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
|
printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
|
||||||
maxwidth, item->name,
|
maxwidth, item->name,
|
||||||
branch_get_color(COLOR_BRANCH_RESET),
|
branch_get_color(COLOR_BRANCH_RESET),
|
||||||
find_unique_abbrev(item->sha1, abbrev), sub);
|
find_unique_abbrev(item->sha1, abbrev), sub);
|
||||||
if (subject)
|
strbuf_release(&subject);
|
||||||
free(subject);
|
|
||||||
} else {
|
} else {
|
||||||
printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
|
printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
|
||||||
branch_get_color(COLOR_BRANCH_RESET));
|
branch_get_color(COLOR_BRANCH_RESET));
|
||||||
|
@ -56,7 +56,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
|
|||||||
else if (ATTR_UNSET(value))
|
else if (ATTR_UNSET(value))
|
||||||
value = "unspecified";
|
value = "unspecified";
|
||||||
|
|
||||||
write_name_quoted("", 0, argv[i], 1, stdout);
|
quote_c_style(argv[i], NULL, stdout, 0);
|
||||||
printf(": %s: %s\n", argv[j+1], value);
|
printf(": %s: %s\n", argv[j+1], value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "strbuf.h"
|
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
|
|
||||||
@ -67,9 +66,7 @@ static void write_tempfile_record(const char *name, int prefix_length)
|
|||||||
fputs(topath[checkout_stage], stdout);
|
fputs(topath[checkout_stage], stdout);
|
||||||
|
|
||||||
putchar('\t');
|
putchar('\t');
|
||||||
write_name_quoted("", 0, name + prefix_length,
|
write_name_quoted(name + prefix_length, stdout, line_termination);
|
||||||
line_termination, stdout);
|
|
||||||
putchar(line_termination);
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
topath[i][0] = 0;
|
topath[i][0] = 0;
|
||||||
@ -271,28 +268,28 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (read_from_stdin) {
|
if (read_from_stdin) {
|
||||||
struct strbuf buf;
|
struct strbuf buf, nbuf;
|
||||||
|
|
||||||
if (all)
|
if (all)
|
||||||
die("git-checkout-index: don't mix '--all' and '--stdin'");
|
die("git-checkout-index: don't mix '--all' and '--stdin'");
|
||||||
strbuf_init(&buf);
|
|
||||||
while (1) {
|
|
||||||
char *path_name;
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
read_line(&buf, stdin, line_termination);
|
strbuf_init(&buf, 0);
|
||||||
if (buf.eof)
|
strbuf_init(&nbuf, 0);
|
||||||
break;
|
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
|
||||||
if (line_termination && buf.buf[0] == '"')
|
const char *p;
|
||||||
path_name = unquote_c_style(buf.buf, NULL);
|
if (line_termination && buf.buf[0] == '"') {
|
||||||
else
|
strbuf_reset(&nbuf);
|
||||||
path_name = buf.buf;
|
if (unquote_c_style(&nbuf, buf.buf, NULL))
|
||||||
p = prefix_path(prefix, prefix_length, path_name);
|
die("line is badly quoted");
|
||||||
checkout_file(p, prefix_length);
|
strbuf_swap(&buf, &nbuf);
|
||||||
if (p < path_name || p > path_name + strlen(path_name))
|
|
||||||
free((char *)p);
|
|
||||||
if (path_name != buf.buf)
|
|
||||||
free(path_name);
|
|
||||||
}
|
}
|
||||||
|
p = prefix_path(prefix, prefix_length, buf.buf);
|
||||||
|
checkout_file(p, prefix_length);
|
||||||
|
if (p < buf.buf || p > buf.buf + buf.len)
|
||||||
|
free((char *)p);
|
||||||
|
}
|
||||||
|
strbuf_release(&nbuf);
|
||||||
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all)
|
if (all)
|
||||||
|
@ -14,36 +14,6 @@
|
|||||||
/*
|
/*
|
||||||
* FIXME! Share the code with "write-tree.c"
|
* FIXME! Share the code with "write-tree.c"
|
||||||
*/
|
*/
|
||||||
static void init_buffer(char **bufp, unsigned int *sizep)
|
|
||||||
{
|
|
||||||
*bufp = xmalloc(BLOCKING);
|
|
||||||
*sizep = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
char one_line[2048];
|
|
||||||
va_list args;
|
|
||||||
int len;
|
|
||||||
unsigned long alloc, size, newsize;
|
|
||||||
char *buf;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
len = vsnprintf(one_line, sizeof(one_line), fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
size = *sizep;
|
|
||||||
newsize = size + len + 1;
|
|
||||||
alloc = (size + 32767) & ~32767;
|
|
||||||
buf = *bufp;
|
|
||||||
if (newsize > alloc) {
|
|
||||||
alloc = (newsize + 32767) & ~32767;
|
|
||||||
buf = xrealloc(buf, alloc);
|
|
||||||
*bufp = buf;
|
|
||||||
}
|
|
||||||
*sizep = newsize - 1;
|
|
||||||
memcpy(buf + size, one_line, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void check_valid(unsigned char *sha1, enum object_type expect)
|
static void check_valid(unsigned char *sha1, enum object_type expect)
|
||||||
{
|
{
|
||||||
enum object_type type = sha1_object_info(sha1, NULL);
|
enum object_type type = sha1_object_info(sha1, NULL);
|
||||||
@ -87,9 +57,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
|||||||
int parents = 0;
|
int parents = 0;
|
||||||
unsigned char tree_sha1[20];
|
unsigned char tree_sha1[20];
|
||||||
unsigned char commit_sha1[20];
|
unsigned char commit_sha1[20];
|
||||||
char comment[1000];
|
struct strbuf buffer;
|
||||||
char *buffer;
|
|
||||||
unsigned int size;
|
|
||||||
int encoding_is_utf8;
|
int encoding_is_utf8;
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_default_config);
|
||||||
@ -118,8 +86,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
|||||||
/* Not having i18n.commitencoding is the same as having utf-8 */
|
/* Not having i18n.commitencoding is the same as having utf-8 */
|
||||||
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
|
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
|
||||||
|
|
||||||
init_buffer(&buffer, &size);
|
strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
|
||||||
add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
|
strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree_sha1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE! This ordering means that the same exact tree merged with a
|
* NOTE! This ordering means that the same exact tree merged with a
|
||||||
@ -127,26 +95,24 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
|||||||
* if everything else stays the same.
|
* if everything else stays the same.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < parents; i++)
|
for (i = 0; i < parents; i++)
|
||||||
add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
|
strbuf_addf(&buffer, "parent %s\n", sha1_to_hex(parent_sha1[i]));
|
||||||
|
|
||||||
/* Person/date information */
|
/* Person/date information */
|
||||||
add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
|
strbuf_addf(&buffer, "author %s\n", git_author_info(1));
|
||||||
add_buffer(&buffer, &size, "committer %s\n", git_committer_info(1));
|
strbuf_addf(&buffer, "committer %s\n", git_committer_info(1));
|
||||||
if (!encoding_is_utf8)
|
if (!encoding_is_utf8)
|
||||||
add_buffer(&buffer, &size,
|
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
|
||||||
"encoding %s\n", git_commit_encoding);
|
strbuf_addch(&buffer, '\n');
|
||||||
add_buffer(&buffer, &size, "\n");
|
|
||||||
|
|
||||||
/* And add the comment */
|
/* And add the comment */
|
||||||
while (fgets(comment, sizeof(comment), stdin) != NULL)
|
if (strbuf_read(&buffer, 0, 0) < 0)
|
||||||
add_buffer(&buffer, &size, "%s", comment);
|
die("git-commit-tree: read returned %s", strerror(errno));
|
||||||
|
|
||||||
/* And check the encoding */
|
/* And check the encoding */
|
||||||
buffer[size] = '\0';
|
if (encoding_is_utf8 && !is_utf8(buffer.buf))
|
||||||
if (encoding_is_utf8 && !is_utf8(buffer))
|
|
||||||
fprintf(stderr, commit_utf8_warn);
|
fprintf(stderr, commit_utf8_warn);
|
||||||
|
|
||||||
if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
|
if (!write_sha1_file(buffer.buf, buffer.len, commit_type, commit_sha1)) {
|
||||||
printf("%s\n", sha1_to_hex(commit_sha1));
|
printf("%s\n", sha1_to_hex(commit_sha1));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -165,15 +165,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
|||||||
{
|
{
|
||||||
int nongit = 0;
|
int nongit = 0;
|
||||||
char* value;
|
char* value;
|
||||||
setup_git_directory_gently(&nongit);
|
const char *file = setup_git_directory_gently(&nongit);
|
||||||
|
|
||||||
while (1 < argc) {
|
while (1 < argc) {
|
||||||
if (!strcmp(argv[1], "--int"))
|
if (!strcmp(argv[1], "--int"))
|
||||||
type = T_INT;
|
type = T_INT;
|
||||||
else if (!strcmp(argv[1], "--bool"))
|
else if (!strcmp(argv[1], "--bool"))
|
||||||
type = T_BOOL;
|
type = T_BOOL;
|
||||||
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
|
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
|
||||||
|
if (argc != 2)
|
||||||
|
usage(git_config_set_usage);
|
||||||
return git_config(show_all_config);
|
return git_config(show_all_config);
|
||||||
|
}
|
||||||
else if (!strcmp(argv[1], "--global")) {
|
else if (!strcmp(argv[1], "--global")) {
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (home) {
|
if (home) {
|
||||||
@ -189,7 +192,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
|||||||
else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
|
else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
usage(git_config_set_usage);
|
usage(git_config_set_usage);
|
||||||
setenv(CONFIG_ENVIRONMENT, argv[2], 1);
|
if (!is_absolute_path(argv[2]) && file)
|
||||||
|
file = prefix_filename(file, strlen(file),
|
||||||
|
argv[2]);
|
||||||
|
else
|
||||||
|
file = argv[2];
|
||||||
|
setenv(CONFIG_ENVIRONMENT, file, 1);
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
@ -3,26 +3,14 @@
|
|||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
|
|
||||||
#define CHUNK_SIZE 1024
|
|
||||||
|
|
||||||
static char *get_stdin(void)
|
static char *get_stdin(void)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
struct strbuf buf;
|
||||||
char *data = xmalloc(CHUNK_SIZE);
|
strbuf_init(&buf, 0);
|
||||||
|
if (strbuf_read(&buf, 0, 1024) < 0) {
|
||||||
while (1) {
|
die("error reading standard input: %s", strerror(errno));
|
||||||
ssize_t cnt = xread(0, data + offset, CHUNK_SIZE);
|
|
||||||
if (cnt < 0)
|
|
||||||
die("error reading standard input: %s",
|
|
||||||
strerror(errno));
|
|
||||||
if (cnt == 0) {
|
|
||||||
data[offset] = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
offset += cnt;
|
return strbuf_detach(&buf, NULL);
|
||||||
data = xrealloc(data, offset + CHUNK_SIZE);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_new(enum object_type type, unsigned char *sha1_new)
|
static void show_new(enum object_type type, unsigned char *sha1_new)
|
||||||
@ -234,19 +222,15 @@ static char *find_local_name(const char *remote_name, const char *refs,
|
|||||||
}
|
}
|
||||||
if (!strncmp(remote_name, ref, len) && ref[len] == ':') {
|
if (!strncmp(remote_name, ref, len) && ref[len] == ':') {
|
||||||
const char *local_part = ref + len + 1;
|
const char *local_part = ref + len + 1;
|
||||||
char *ret;
|
|
||||||
int retlen;
|
int retlen;
|
||||||
|
|
||||||
if (!next)
|
if (!next)
|
||||||
retlen = strlen(local_part);
|
retlen = strlen(local_part);
|
||||||
else
|
else
|
||||||
retlen = next - local_part;
|
retlen = next - local_part;
|
||||||
ret = xmalloc(retlen + 1);
|
|
||||||
memcpy(ret, local_part, retlen);
|
|
||||||
ret[retlen] = 0;
|
|
||||||
*force_p = single_force;
|
*force_p = single_force;
|
||||||
*not_for_merge_p = not_for_merge;
|
*not_for_merge_p = not_for_merge;
|
||||||
return ret;
|
return xmemdupz(local_part, retlen);
|
||||||
}
|
}
|
||||||
ref = next;
|
ref = next;
|
||||||
}
|
}
|
||||||
|
@ -140,12 +140,10 @@ static int handle_line(char *line)
|
|||||||
if (!strcmp(".", src) || !strcmp(src, origin)) {
|
if (!strcmp(".", src) || !strcmp(src, origin)) {
|
||||||
int len = strlen(origin);
|
int len = strlen(origin);
|
||||||
if (origin[0] == '\'' && origin[len - 1] == '\'') {
|
if (origin[0] == '\'' && origin[len - 1] == '\'') {
|
||||||
char *new_origin = xmalloc(len - 1);
|
origin = xmemdupz(origin + 1, len - 2);
|
||||||
memcpy(new_origin, origin + 1, len - 2);
|
} else {
|
||||||
new_origin[len - 2] = 0;
|
|
||||||
origin = new_origin;
|
|
||||||
} else
|
|
||||||
origin = xstrdup(origin);
|
origin = xstrdup(origin);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
|
char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
|
||||||
sprintf(new_origin, "%s of %s", origin, src);
|
sprintf(new_origin, "%s of %s", origin, src);
|
||||||
@ -211,14 +209,11 @@ static void shortlog(const char *name, unsigned char *sha1,
|
|||||||
|
|
||||||
bol += 2;
|
bol += 2;
|
||||||
eol = strchr(bol, '\n');
|
eol = strchr(bol, '\n');
|
||||||
|
|
||||||
if (eol) {
|
if (eol) {
|
||||||
int len = eol - bol;
|
oneline = xmemdupz(bol, eol - bol);
|
||||||
oneline = xmalloc(len + 1);
|
} else {
|
||||||
memcpy(oneline, bol, len);
|
|
||||||
oneline[len] = 0;
|
|
||||||
} else
|
|
||||||
oneline = xstrdup(bol);
|
oneline = xstrdup(bol);
|
||||||
|
}
|
||||||
append_to_list(&subjects, oneline, NULL);
|
append_to_list(&subjects, oneline, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ static struct {
|
|||||||
{ "objectsize", FIELD_ULONG },
|
{ "objectsize", FIELD_ULONG },
|
||||||
{ "objectname" },
|
{ "objectname" },
|
||||||
{ "tree" },
|
{ "tree" },
|
||||||
{ "parent" }, /* NEEDSWORK: how to address 2nd and later parents? */
|
{ "parent" },
|
||||||
{ "numparent", FIELD_ULONG },
|
{ "numparent", FIELD_ULONG },
|
||||||
{ "object" },
|
{ "object" },
|
||||||
{ "type" },
|
{ "type" },
|
||||||
@ -87,7 +87,6 @@ static int used_atom_cnt, sort_atom_limit, need_tagged;
|
|||||||
static int parse_atom(const char *atom, const char *ep)
|
static int parse_atom(const char *atom, const char *ep)
|
||||||
{
|
{
|
||||||
const char *sp;
|
const char *sp;
|
||||||
char *n;
|
|
||||||
int i, at;
|
int i, at;
|
||||||
|
|
||||||
sp = atom;
|
sp = atom;
|
||||||
@ -106,7 +105,16 @@ static int parse_atom(const char *atom, const char *ep)
|
|||||||
/* Is the atom a valid one? */
|
/* Is the atom a valid one? */
|
||||||
for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
|
for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
|
||||||
int len = strlen(valid_atom[i].name);
|
int len = strlen(valid_atom[i].name);
|
||||||
if (len == ep - sp && !memcmp(valid_atom[i].name, sp, len))
|
/*
|
||||||
|
* If the atom name has a colon, strip it and everything after
|
||||||
|
* it off - it specifies the format for this entry, and
|
||||||
|
* shouldn't be used for checking against the valid_atom
|
||||||
|
* table.
|
||||||
|
*/
|
||||||
|
const char *formatp = strchr(sp, ':');
|
||||||
|
if (!formatp || ep < formatp)
|
||||||
|
formatp = ep;
|
||||||
|
if (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,10 +128,7 @@ static int parse_atom(const char *atom, const char *ep)
|
|||||||
(sizeof *used_atom) * used_atom_cnt);
|
(sizeof *used_atom) * used_atom_cnt);
|
||||||
used_atom_type = xrealloc(used_atom_type,
|
used_atom_type = xrealloc(used_atom_type,
|
||||||
(sizeof(*used_atom_type) * used_atom_cnt));
|
(sizeof(*used_atom_type) * used_atom_cnt));
|
||||||
n = xmalloc(ep - atom + 1);
|
used_atom[at] = xmemdupz(atom, ep - atom);
|
||||||
memcpy(n, atom, ep - atom);
|
|
||||||
n[ep-atom] = 0;
|
|
||||||
used_atom[at] = n;
|
|
||||||
used_atom_type[at] = valid_atom[i].cmp_type;
|
used_atom_type[at] = valid_atom[i].cmp_type;
|
||||||
return at;
|
return at;
|
||||||
}
|
}
|
||||||
@ -262,24 +267,26 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
|
|||||||
}
|
}
|
||||||
if (!strcmp(name, "numparent")) {
|
if (!strcmp(name, "numparent")) {
|
||||||
char *s = xmalloc(40);
|
char *s = xmalloc(40);
|
||||||
|
v->ul = num_parents(commit);
|
||||||
sprintf(s, "%lu", v->ul);
|
sprintf(s, "%lu", v->ul);
|
||||||
v->s = s;
|
v->s = s;
|
||||||
v->ul = num_parents(commit);
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(name, "parent")) {
|
else if (!strcmp(name, "parent")) {
|
||||||
int num = num_parents(commit);
|
int num = num_parents(commit);
|
||||||
int i;
|
int i;
|
||||||
struct commit_list *parents;
|
struct commit_list *parents;
|
||||||
char *s = xmalloc(42 * num);
|
char *s = xmalloc(41 * num + 1);
|
||||||
v->s = s;
|
v->s = s;
|
||||||
for (i = 0, parents = commit->parents;
|
for (i = 0, parents = commit->parents;
|
||||||
parents;
|
parents;
|
||||||
parents = parents->next, i = i + 42) {
|
parents = parents->next, i = i + 41) {
|
||||||
struct commit *parent = parents->item;
|
struct commit *parent = parents->item;
|
||||||
strcpy(s+i, sha1_to_hex(parent->object.sha1));
|
strcpy(s+i, sha1_to_hex(parent->object.sha1));
|
||||||
if (parents->next)
|
if (parents->next)
|
||||||
s[i+40] = ' ';
|
s[i+40] = ' ';
|
||||||
}
|
}
|
||||||
|
if (!i)
|
||||||
|
*s = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,54 +312,50 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un
|
|||||||
static const char *copy_line(const char *buf)
|
static const char *copy_line(const char *buf)
|
||||||
{
|
{
|
||||||
const char *eol = strchr(buf, '\n');
|
const char *eol = strchr(buf, '\n');
|
||||||
char *line;
|
|
||||||
int len;
|
|
||||||
if (!eol)
|
if (!eol)
|
||||||
return "";
|
return "";
|
||||||
len = eol - buf;
|
return xmemdupz(buf, eol - buf);
|
||||||
line = xmalloc(len + 1);
|
|
||||||
memcpy(line, buf, len);
|
|
||||||
line[len] = 0;
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *copy_name(const char *buf)
|
static const char *copy_name(const char *buf)
|
||||||
{
|
{
|
||||||
const char *eol = strchr(buf, '\n');
|
const char *cp;
|
||||||
const char *eoname = strstr(buf, " <");
|
for (cp = buf; *cp && *cp != '\n'; cp++) {
|
||||||
char *line;
|
if (!strncmp(cp, " <", 2))
|
||||||
int len;
|
return xmemdupz(buf, cp - buf);
|
||||||
if (!(eoname && eol && eoname < eol))
|
}
|
||||||
return "";
|
return "";
|
||||||
len = eoname - buf;
|
|
||||||
line = xmalloc(len + 1);
|
|
||||||
memcpy(line, buf, len);
|
|
||||||
line[len] = 0;
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *copy_email(const char *buf)
|
static const char *copy_email(const char *buf)
|
||||||
{
|
{
|
||||||
const char *email = strchr(buf, '<');
|
const char *email = strchr(buf, '<');
|
||||||
const char *eoemail = strchr(email, '>');
|
const char *eoemail = strchr(email, '>');
|
||||||
char *line;
|
|
||||||
int len;
|
|
||||||
if (!email || !eoemail)
|
if (!email || !eoemail)
|
||||||
return "";
|
return "";
|
||||||
eoemail++;
|
return xmemdupz(email, eoemail + 1 - email);
|
||||||
len = eoemail - email;
|
|
||||||
line = xmalloc(len + 1);
|
|
||||||
memcpy(line, email, len);
|
|
||||||
line[len] = 0;
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void grab_date(const char *buf, struct atom_value *v)
|
static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
|
||||||
{
|
{
|
||||||
const char *eoemail = strstr(buf, "> ");
|
const char *eoemail = strstr(buf, "> ");
|
||||||
char *zone;
|
char *zone;
|
||||||
unsigned long timestamp;
|
unsigned long timestamp;
|
||||||
long tz;
|
long tz;
|
||||||
|
enum date_mode date_mode = DATE_NORMAL;
|
||||||
|
const char *formatp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We got here because atomname ends in "date" or "date<something>";
|
||||||
|
* it's not possible that <something> is not ":<format>" because
|
||||||
|
* parse_atom() wouldn't have allowed it, so we can assume that no
|
||||||
|
* ":" means no format is specified, and use the default.
|
||||||
|
*/
|
||||||
|
formatp = strchr(atomname, ':');
|
||||||
|
if (formatp != NULL) {
|
||||||
|
formatp++;
|
||||||
|
date_mode = parse_date_format(formatp);
|
||||||
|
}
|
||||||
|
|
||||||
if (!eoemail)
|
if (!eoemail)
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -362,7 +365,7 @@ static void grab_date(const char *buf, struct atom_value *v)
|
|||||||
tz = strtol(zone, NULL, 10);
|
tz = strtol(zone, NULL, 10);
|
||||||
if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
|
if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
|
||||||
goto bad;
|
goto bad;
|
||||||
v->s = xstrdup(show_date(timestamp, tz, 0));
|
v->s = xstrdup(show_date(timestamp, tz, date_mode));
|
||||||
v->ul = timestamp;
|
v->ul = timestamp;
|
||||||
return;
|
return;
|
||||||
bad:
|
bad:
|
||||||
@ -389,7 +392,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
|
|||||||
if (name[wholen] != 0 &&
|
if (name[wholen] != 0 &&
|
||||||
strcmp(name + wholen, "name") &&
|
strcmp(name + wholen, "name") &&
|
||||||
strcmp(name + wholen, "email") &&
|
strcmp(name + wholen, "email") &&
|
||||||
strcmp(name + wholen, "date"))
|
prefixcmp(name + wholen, "date"))
|
||||||
continue;
|
continue;
|
||||||
if (!wholine)
|
if (!wholine)
|
||||||
wholine = find_wholine(who, wholen, buf, sz);
|
wholine = find_wholine(who, wholen, buf, sz);
|
||||||
@ -401,8 +404,8 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
|
|||||||
v->s = copy_name(wholine);
|
v->s = copy_name(wholine);
|
||||||
else if (!strcmp(name + wholen, "email"))
|
else if (!strcmp(name + wholen, "email"))
|
||||||
v->s = copy_email(wholine);
|
v->s = copy_email(wholine);
|
||||||
else if (!strcmp(name + wholen, "date"))
|
else if (!prefixcmp(name + wholen, "date"))
|
||||||
grab_date(wholine, v);
|
grab_date(wholine, v, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For a tag or a commit object, if "creator" or "creatordate" is
|
/* For a tag or a commit object, if "creator" or "creatordate" is
|
||||||
@ -422,8 +425,8 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
|
|||||||
if (deref)
|
if (deref)
|
||||||
name++;
|
name++;
|
||||||
|
|
||||||
if (!strcmp(name, "creatordate"))
|
if (!prefixcmp(name, "creatordate"))
|
||||||
grab_date(wholine, v);
|
grab_date(wholine, v, name);
|
||||||
else if (!strcmp(name, "creator"))
|
else if (!strcmp(name, "creator"))
|
||||||
v->s = copy_line(wholine);
|
v->s = copy_line(wholine);
|
||||||
}
|
}
|
||||||
|
137
builtin-gc.c
137
builtin-gc.c
@ -20,11 +20,13 @@ static const char builtin_gc_usage[] = "git-gc [--prune] [--aggressive]";
|
|||||||
|
|
||||||
static int pack_refs = 1;
|
static int pack_refs = 1;
|
||||||
static int aggressive_window = -1;
|
static int aggressive_window = -1;
|
||||||
|
static int gc_auto_threshold = 6700;
|
||||||
|
static int gc_auto_pack_limit = 20;
|
||||||
|
|
||||||
#define MAX_ADD 10
|
#define MAX_ADD 10
|
||||||
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
|
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
|
||||||
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
|
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
|
||||||
static const char *argv_repack[MAX_ADD] = {"repack", "-a", "-d", "-l", NULL};
|
static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
|
||||||
static const char *argv_prune[] = {"prune", NULL};
|
static const char *argv_prune[] = {"prune", NULL};
|
||||||
static const char *argv_rerere[] = {"rerere", "gc", NULL};
|
static const char *argv_rerere[] = {"rerere", "gc", NULL};
|
||||||
|
|
||||||
@ -41,6 +43,14 @@ static int gc_config(const char *var, const char *value)
|
|||||||
aggressive_window = git_config_int(var, value);
|
aggressive_window = git_config_int(var, value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(var, "gc.auto")) {
|
||||||
|
gc_auto_threshold = git_config_int(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(var, "gc.autopacklimit")) {
|
||||||
|
gc_auto_pack_limit = git_config_int(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return git_default_config(var, value);
|
return git_default_config(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +67,107 @@ static void append_option(const char **cmd, const char *opt, int max_length)
|
|||||||
cmd[i] = NULL;
|
cmd[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int too_many_loose_objects(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Quickly check if a "gc" is needed, by estimating how
|
||||||
|
* many loose objects there are. Because SHA-1 is evenly
|
||||||
|
* distributed, we can check only one and get a reasonable
|
||||||
|
* estimate.
|
||||||
|
*/
|
||||||
|
char path[PATH_MAX];
|
||||||
|
const char *objdir = get_object_directory();
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
int auto_threshold;
|
||||||
|
int num_loose = 0;
|
||||||
|
int needed = 0;
|
||||||
|
|
||||||
|
if (gc_auto_threshold <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) {
|
||||||
|
warning("insanely long object directory %.*s", 50, objdir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto_threshold = (gc_auto_threshold + 255) / 256;
|
||||||
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
|
if (strspn(ent->d_name, "0123456789abcdef") != 38 ||
|
||||||
|
ent->d_name[38] != '\0')
|
||||||
|
continue;
|
||||||
|
if (++num_loose > auto_threshold) {
|
||||||
|
needed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
return needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int too_many_packs(void)
|
||||||
|
{
|
||||||
|
struct packed_git *p;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
if (gc_auto_pack_limit <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
prepare_packed_git();
|
||||||
|
for (cnt = 0, p = packed_git; p; p = p->next) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
size_t len;
|
||||||
|
int keep;
|
||||||
|
|
||||||
|
if (!p->pack_local)
|
||||||
|
continue;
|
||||||
|
len = strlen(p->pack_name);
|
||||||
|
if (PATH_MAX <= len + 1)
|
||||||
|
continue; /* oops, give up */
|
||||||
|
memcpy(path, p->pack_name, len-5);
|
||||||
|
memcpy(path + len - 5, ".keep", 6);
|
||||||
|
keep = access(p->pack_name, F_OK) && (errno == ENOENT);
|
||||||
|
if (keep)
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* Perhaps check the size of the pack and count only
|
||||||
|
* very small ones here?
|
||||||
|
*/
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return gc_auto_pack_limit <= cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int need_to_gc(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Setting gc.auto and gc.autopacklimit to 0 or negative can
|
||||||
|
* disable the automatic gc.
|
||||||
|
*/
|
||||||
|
if (gc_auto_threshold <= 0 && gc_auto_pack_limit <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are too many loose objects, but not too many
|
||||||
|
* packs, we run "repack -d -l". If there are too many packs,
|
||||||
|
* we run "repack -A -d -l". Otherwise we tell the caller
|
||||||
|
* there is no need.
|
||||||
|
*/
|
||||||
|
if (too_many_packs())
|
||||||
|
append_option(argv_repack, "-A", MAX_ADD);
|
||||||
|
else if (!too_many_loose_objects())
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_gc(int argc, const char **argv, const char *prefix)
|
int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int prune = 0;
|
int prune = 0;
|
||||||
|
int auto_gc = 0;
|
||||||
char buf[80];
|
char buf[80];
|
||||||
|
|
||||||
git_config(gc_config);
|
git_config(gc_config);
|
||||||
@ -82,12 +189,34 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* perhaps other parameters later... */
|
if (!strcmp(arg, "--auto")) {
|
||||||
|
auto_gc = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i != argc)
|
if (i != argc)
|
||||||
usage(builtin_gc_usage);
|
usage(builtin_gc_usage);
|
||||||
|
|
||||||
|
if (auto_gc) {
|
||||||
|
/*
|
||||||
|
* Auto-gc should be least intrusive as possible.
|
||||||
|
*/
|
||||||
|
prune = 0;
|
||||||
|
if (!need_to_gc())
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Use safer (for shared repos) "-A" option to
|
||||||
|
* repack when not pruning. Auto-gc makes its
|
||||||
|
* own decision.
|
||||||
|
*/
|
||||||
|
if (prune)
|
||||||
|
append_option(argv_repack, "-a", MAX_ADD);
|
||||||
|
else
|
||||||
|
append_option(argv_repack, "-A", MAX_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
|
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
|
||||||
return error(FAILED_RUN, argv_pack_refs[0]);
|
return error(FAILED_RUN, argv_pack_refs[0]);
|
||||||
|
|
||||||
@ -103,5 +232,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
|||||||
if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
|
if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
|
||||||
return error(FAILED_RUN, argv_rerere[0]);
|
return error(FAILED_RUN, argv_rerere[0]);
|
||||||
|
|
||||||
|
if (auto_gc && too_many_loose_objects())
|
||||||
|
warning("There are too many unreachable loose objects; "
|
||||||
|
"run 'git prune' to remove them.");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -441,8 +441,6 @@ static const char *clean_message_id(const char *msg_id)
|
|||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
const char *a, *z, *m;
|
const char *a, *z, *m;
|
||||||
char *n;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
m = msg_id;
|
m = msg_id;
|
||||||
while ((ch = *m) && (isspace(ch) || (ch == '<')))
|
while ((ch = *m) && (isspace(ch) || (ch == '<')))
|
||||||
@ -458,11 +456,7 @@ static const char *clean_message_id(const char *msg_id)
|
|||||||
die("insane in-reply-to: %s", msg_id);
|
die("insane in-reply-to: %s", msg_id);
|
||||||
if (++z == m)
|
if (++z == m)
|
||||||
return a;
|
return a;
|
||||||
len = z - a;
|
return xmemdupz(a, z - a);
|
||||||
n = xmalloc(len + 1);
|
|
||||||
memcpy(n, a, len);
|
|
||||||
n[len] = 0;
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||||
@ -541,9 +535,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||||||
endpos = strchr(committer, '>');
|
endpos = strchr(committer, '>');
|
||||||
if (!endpos)
|
if (!endpos)
|
||||||
die("bogos committer info %s\n", committer);
|
die("bogos committer info %s\n", committer);
|
||||||
add_signoff = xmalloc(endpos - committer + 2);
|
add_signoff = xmemdupz(committer, endpos - committer + 1);
|
||||||
memcpy(add_signoff, committer, endpos - committer + 1);
|
|
||||||
add_signoff[endpos - committer + 1] = 0;
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[i], "--attach")) {
|
else if (!strcmp(argv[i], "--attach")) {
|
||||||
rev.mime_boundary = git_version_string;
|
rev.mime_boundary = git_version_string;
|
||||||
@ -792,13 +784,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
|
|||||||
sign = '-';
|
sign = '-';
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
char *buf = NULL;
|
struct strbuf buf;
|
||||||
unsigned long buflen = 0;
|
strbuf_init(&buf, 0);
|
||||||
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
|
pretty_print_commit(CMIT_FMT_ONELINE, commit,
|
||||||
&buf, &buflen, 0, NULL, NULL, 0);
|
&buf, 0, NULL, NULL, 0);
|
||||||
printf("%c %s %s\n", sign,
|
printf("%c %s %s\n", sign,
|
||||||
sha1_to_hex(commit->object.sha1), buf);
|
sha1_to_hex(commit->object.sha1), buf.buf);
|
||||||
free(buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("%c %s\n", sign,
|
printf("%c %s\n", sign,
|
||||||
|
@ -84,8 +84,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
fputs(tag, stdout);
|
fputs(tag, stdout);
|
||||||
write_name_quoted("", 0, ent->name + offset, line_terminator, stdout);
|
write_name_quoted(ent->name + offset, stdout, line_terminator);
|
||||||
putchar(line_terminator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_other_files(struct dir_struct *dir)
|
static void show_other_files(struct dir_struct *dir)
|
||||||
@ -208,21 +207,15 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
|
|||||||
|
|
||||||
if (!show_stage) {
|
if (!show_stage) {
|
||||||
fputs(tag, stdout);
|
fputs(tag, stdout);
|
||||||
write_name_quoted("", 0, ce->name + offset,
|
} else {
|
||||||
line_terminator, stdout);
|
|
||||||
putchar(line_terminator);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("%s%06o %s %d\t",
|
printf("%s%06o %s %d\t",
|
||||||
tag,
|
tag,
|
||||||
ntohl(ce->ce_mode),
|
ntohl(ce->ce_mode),
|
||||||
abbrev ? find_unique_abbrev(ce->sha1,abbrev)
|
abbrev ? find_unique_abbrev(ce->sha1,abbrev)
|
||||||
: sha1_to_hex(ce->sha1),
|
: sha1_to_hex(ce->sha1),
|
||||||
ce_stage(ce));
|
ce_stage(ce));
|
||||||
write_name_quoted("", 0, ce->name + offset,
|
|
||||||
line_terminator, stdout);
|
|
||||||
putchar(line_terminator);
|
|
||||||
}
|
}
|
||||||
|
write_name_quoted(ce->name + offset, stdout, line_terminator);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_files(struct dir_struct *dir, const char *prefix)
|
static void show_files(struct dir_struct *dir, const char *prefix)
|
||||||
@ -280,7 +273,8 @@ static void prune_cache(const char *prefix)
|
|||||||
|
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
pos = -pos-1;
|
pos = -pos-1;
|
||||||
active_cache += pos;
|
memmove(active_cache, active_cache + pos,
|
||||||
|
(active_nr - pos) * sizeof(struct cache_entry *));
|
||||||
active_nr -= pos;
|
active_nr -= pos;
|
||||||
first = 0;
|
first = 0;
|
||||||
last = active_nr;
|
last = active_nr;
|
||||||
@ -299,7 +293,6 @@ static void prune_cache(const char *prefix)
|
|||||||
static const char *verify_pathspec(const char *prefix)
|
static const char *verify_pathspec(const char *prefix)
|
||||||
{
|
{
|
||||||
const char **p, *n, *prev;
|
const char **p, *n, *prev;
|
||||||
char *real_prefix;
|
|
||||||
unsigned long max;
|
unsigned long max;
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
@ -326,14 +319,8 @@ static const char *verify_pathspec(const char *prefix)
|
|||||||
if (prefix_offset > max || memcmp(prev, prefix, prefix_offset))
|
if (prefix_offset > max || memcmp(prev, prefix, prefix_offset))
|
||||||
die("git-ls-files: cannot generate relative filenames containing '..'");
|
die("git-ls-files: cannot generate relative filenames containing '..'");
|
||||||
|
|
||||||
real_prefix = NULL;
|
|
||||||
prefix_len = max;
|
prefix_len = max;
|
||||||
if (max) {
|
return max ? xmemdupz(prev, max) : NULL;
|
||||||
real_prefix = xmalloc(max + 1);
|
|
||||||
memcpy(real_prefix, prev, max);
|
|
||||||
real_prefix[max] = 0;
|
|
||||||
}
|
|
||||||
return real_prefix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -112,10 +112,8 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
|
|||||||
abbrev ? find_unique_abbrev(sha1, abbrev)
|
abbrev ? find_unique_abbrev(sha1, abbrev)
|
||||||
: sha1_to_hex(sha1));
|
: sha1_to_hex(sha1));
|
||||||
}
|
}
|
||||||
write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
|
write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
|
||||||
pathname,
|
pathname, stdout, line_termination);
|
||||||
line_termination, stdout);
|
|
||||||
putchar(line_termination);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,7 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
|||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
int length = strlen(result[i]);
|
int length = strlen(result[i]);
|
||||||
if (length > 0 && result[i][length - 1] == '/') {
|
if (length > 0 && result[i][length - 1] == '/') {
|
||||||
char *without_slash = xmalloc(length);
|
result[i] = xmemdupz(result[i], length - 1);
|
||||||
memcpy(without_slash, result[i], length - 1);
|
|
||||||
without_slash[length - 1] = '\0';
|
|
||||||
result[i] = without_slash;
|
|
||||||
}
|
}
|
||||||
if (base_name) {
|
if (base_name) {
|
||||||
const char *last_slash = strrchr(result[i], '/');
|
const char *last_slash = strrchr(result[i], '/');
|
||||||
|
@ -25,7 +25,7 @@ git-pack-objects [{ -q | --progress | --all-progress }] \n\
|
|||||||
[--window=N] [--window-memory=N] [--depth=N] \n\
|
[--window=N] [--window-memory=N] [--depth=N] \n\
|
||||||
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
|
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
|
||||||
[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
|
[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
|
||||||
[--stdout | base-name] [<ref-list | <object-list]";
|
[--stdout | base-name] [--keep-unreachable] [<ref-list | <object-list]";
|
||||||
|
|
||||||
struct object_entry {
|
struct object_entry {
|
||||||
struct pack_idx_entry idx;
|
struct pack_idx_entry idx;
|
||||||
@ -61,7 +61,7 @@ static struct object_entry **written_list;
|
|||||||
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
|
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
|
||||||
|
|
||||||
static int non_empty;
|
static int non_empty;
|
||||||
static int no_reuse_delta, no_reuse_object;
|
static int no_reuse_delta, no_reuse_object, keep_unreachable;
|
||||||
static int local;
|
static int local;
|
||||||
static int incremental;
|
static int incremental;
|
||||||
static int allow_ofs_delta;
|
static int allow_ofs_delta;
|
||||||
@ -1807,15 +1807,19 @@ static void read_object_list_from_stdin(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define OBJECT_ADDED (1u<<20)
|
||||||
|
|
||||||
static void show_commit(struct commit *commit)
|
static void show_commit(struct commit *commit)
|
||||||
{
|
{
|
||||||
add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
|
add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
|
||||||
|
commit->object.flags |= OBJECT_ADDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_object(struct object_array_entry *p)
|
static void show_object(struct object_array_entry *p)
|
||||||
{
|
{
|
||||||
add_preferred_base_object(p->name);
|
add_preferred_base_object(p->name);
|
||||||
add_object_entry(p->item->sha1, p->item->type, p->name, 0);
|
add_object_entry(p->item->sha1, p->item->type, p->name, 0);
|
||||||
|
p->item->flags |= OBJECT_ADDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_edge(struct commit *commit)
|
static void show_edge(struct commit *commit)
|
||||||
@ -1823,6 +1827,86 @@ static void show_edge(struct commit *commit)
|
|||||||
add_preferred_base(commit->object.sha1);
|
add_preferred_base(commit->object.sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct in_pack_object {
|
||||||
|
off_t offset;
|
||||||
|
struct object *object;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct in_pack {
|
||||||
|
int alloc;
|
||||||
|
int nr;
|
||||||
|
struct in_pack_object *array;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mark_in_pack_object(struct object *object, struct packed_git *p, struct in_pack *in_pack)
|
||||||
|
{
|
||||||
|
in_pack->array[in_pack->nr].offset = find_pack_entry_one(object->sha1, p);
|
||||||
|
in_pack->array[in_pack->nr].object = object;
|
||||||
|
in_pack->nr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare the objects in the offset order, in order to emulate the
|
||||||
|
* "git-rev-list --objects" output that produced the pack originally.
|
||||||
|
*/
|
||||||
|
static int ofscmp(const void *a_, const void *b_)
|
||||||
|
{
|
||||||
|
struct in_pack_object *a = (struct in_pack_object *)a_;
|
||||||
|
struct in_pack_object *b = (struct in_pack_object *)b_;
|
||||||
|
|
||||||
|
if (a->offset < b->offset)
|
||||||
|
return -1;
|
||||||
|
else if (a->offset > b->offset)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return hashcmp(a->object->sha1, b->object->sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_objects_in_unpacked_packs(struct rev_info *revs)
|
||||||
|
{
|
||||||
|
struct packed_git *p;
|
||||||
|
struct in_pack in_pack;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
memset(&in_pack, 0, sizeof(in_pack));
|
||||||
|
|
||||||
|
for (p = packed_git; p; p = p->next) {
|
||||||
|
const unsigned char *sha1;
|
||||||
|
struct object *o;
|
||||||
|
|
||||||
|
for (i = 0; i < revs->num_ignore_packed; i++) {
|
||||||
|
if (matches_pack_name(p, revs->ignore_packed[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (revs->num_ignore_packed <= i)
|
||||||
|
continue;
|
||||||
|
if (open_pack_index(p))
|
||||||
|
die("cannot open pack index");
|
||||||
|
|
||||||
|
ALLOC_GROW(in_pack.array,
|
||||||
|
in_pack.nr + p->num_objects,
|
||||||
|
in_pack.alloc);
|
||||||
|
|
||||||
|
for (i = 0; i < p->num_objects; i++) {
|
||||||
|
sha1 = nth_packed_object_sha1(p, i);
|
||||||
|
o = lookup_unknown_object(sha1);
|
||||||
|
if (!(o->flags & OBJECT_ADDED))
|
||||||
|
mark_in_pack_object(o, p, &in_pack);
|
||||||
|
o->flags |= OBJECT_ADDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_pack.nr) {
|
||||||
|
qsort(in_pack.array, in_pack.nr, sizeof(in_pack.array[0]),
|
||||||
|
ofscmp);
|
||||||
|
for (i = 0; i < in_pack.nr; i++) {
|
||||||
|
struct object *o = in_pack.array[i].object;
|
||||||
|
add_object_entry(o->sha1, o->type, "", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(in_pack.array);
|
||||||
|
}
|
||||||
|
|
||||||
static void get_object_list(int ac, const char **av)
|
static void get_object_list(int ac, const char **av)
|
||||||
{
|
{
|
||||||
struct rev_info revs;
|
struct rev_info revs;
|
||||||
@ -1854,6 +1938,9 @@ static void get_object_list(int ac, const char **av)
|
|||||||
prepare_revision_walk(&revs);
|
prepare_revision_walk(&revs);
|
||||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||||
traverse_commit_list(&revs, show_commit, show_object);
|
traverse_commit_list(&revs, show_commit, show_object);
|
||||||
|
|
||||||
|
if (keep_unreachable)
|
||||||
|
add_objects_in_unpacked_packs(&revs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adjust_perm(const char *path, mode_t mode)
|
static int adjust_perm(const char *path, mode_t mode)
|
||||||
@ -1983,6 +2070,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
use_internal_rev_list = 1;
|
use_internal_rev_list = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp("--keep-unreachable", arg)) {
|
||||||
|
keep_unreachable = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp("--unpacked", arg) ||
|
if (!strcmp("--unpacked", arg) ||
|
||||||
!prefixcmp(arg, "--unpacked=") ||
|
!prefixcmp(arg, "--unpacked=") ||
|
||||||
!strcmp("--reflog", arg) ||
|
!strcmp("--reflog", arg) ||
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
|
|
||||||
static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
|
static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
|
||||||
|
|
||||||
static int all, thin, verbose;
|
static int all, thin, verbose;
|
||||||
static const char *receivepack;
|
static const char *receivepack;
|
||||||
@ -107,6 +107,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
|
|||||||
flags |= TRANSPORT_PUSH_ALL;
|
flags |= TRANSPORT_PUSH_ALL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--dry-run")) {
|
||||||
|
flags |= TRANSPORT_PUSH_DRY_RUN;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp(arg, "--tags")) {
|
if (!strcmp(arg, "--tags")) {
|
||||||
add_refspec("refs/tags/*");
|
add_refspec("refs/tags/*");
|
||||||
continue;
|
continue;
|
||||||
|
@ -66,40 +66,15 @@ static int write_rr(struct path_list *rr, int out_fd)
|
|||||||
return commit_lock_file(&write_lock);
|
return commit_lock_file(&write_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct buffer {
|
|
||||||
char *ptr;
|
|
||||||
int nr, alloc;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void append_line(struct buffer *buffer, const char *line)
|
|
||||||
{
|
|
||||||
int len = strlen(line);
|
|
||||||
|
|
||||||
if (buffer->nr + len > buffer->alloc) {
|
|
||||||
buffer->alloc = alloc_nr(buffer->nr + len);
|
|
||||||
buffer->ptr = xrealloc(buffer->ptr, buffer->alloc);
|
|
||||||
}
|
|
||||||
memcpy(buffer->ptr + buffer->nr, line, len);
|
|
||||||
buffer->nr += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clear_buffer(struct buffer *buffer)
|
|
||||||
{
|
|
||||||
free(buffer->ptr);
|
|
||||||
buffer->ptr = NULL;
|
|
||||||
buffer->nr = buffer->alloc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_file(const char *path,
|
static int handle_file(const char *path,
|
||||||
unsigned char *sha1, const char *output)
|
unsigned char *sha1, const char *output)
|
||||||
{
|
{
|
||||||
SHA_CTX ctx;
|
SHA_CTX ctx;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int hunk = 0, hunk_no = 0;
|
int hunk = 0, hunk_no = 0;
|
||||||
struct buffer minus = { NULL, 0, 0 }, plus = { NULL, 0, 0 };
|
struct strbuf one, two;
|
||||||
struct buffer *one = &minus, *two = +
|
|
||||||
FILE *f = fopen(path, "r");
|
FILE *f = fopen(path, "r");
|
||||||
FILE *out;
|
FILE *out = NULL;
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
return error("Could not open %s", path);
|
return error("Could not open %s", path);
|
||||||
@ -110,51 +85,50 @@ static int handle_file(const char *path,
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
return error("Could not write %s", output);
|
return error("Could not write %s", output);
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
out = NULL;
|
|
||||||
|
|
||||||
if (sha1)
|
if (sha1)
|
||||||
SHA1_Init(&ctx);
|
SHA1_Init(&ctx);
|
||||||
|
|
||||||
|
strbuf_init(&one, 0);
|
||||||
|
strbuf_init(&two, 0);
|
||||||
while (fgets(buf, sizeof(buf), f)) {
|
while (fgets(buf, sizeof(buf), f)) {
|
||||||
if (!prefixcmp(buf, "<<<<<<< "))
|
if (!prefixcmp(buf, "<<<<<<< "))
|
||||||
hunk = 1;
|
hunk = 1;
|
||||||
else if (!prefixcmp(buf, "======="))
|
else if (!prefixcmp(buf, "======="))
|
||||||
hunk = 2;
|
hunk = 2;
|
||||||
else if (!prefixcmp(buf, ">>>>>>> ")) {
|
else if (!prefixcmp(buf, ">>>>>>> ")) {
|
||||||
int one_is_longer = (one->nr > two->nr);
|
int cmp = strbuf_cmp(&one, &two);
|
||||||
int common_len = one_is_longer ? two->nr : one->nr;
|
|
||||||
int cmp = memcmp(one->ptr, two->ptr, common_len);
|
|
||||||
|
|
||||||
hunk_no++;
|
hunk_no++;
|
||||||
hunk = 0;
|
hunk = 0;
|
||||||
if ((cmp > 0) || ((cmp == 0) && one_is_longer)) {
|
if (cmp > 0) {
|
||||||
struct buffer *swap = one;
|
strbuf_swap(&one, &two);
|
||||||
one = two;
|
|
||||||
two = swap;
|
|
||||||
}
|
}
|
||||||
if (out) {
|
if (out) {
|
||||||
fputs("<<<<<<<\n", out);
|
fputs("<<<<<<<\n", out);
|
||||||
fwrite(one->ptr, one->nr, 1, out);
|
fwrite(one.buf, one.len, 1, out);
|
||||||
fputs("=======\n", out);
|
fputs("=======\n", out);
|
||||||
fwrite(two->ptr, two->nr, 1, out);
|
fwrite(two.buf, two.len, 1, out);
|
||||||
fputs(">>>>>>>\n", out);
|
fputs(">>>>>>>\n", out);
|
||||||
}
|
}
|
||||||
if (sha1) {
|
if (sha1) {
|
||||||
SHA1_Update(&ctx, one->ptr, one->nr);
|
SHA1_Update(&ctx, one.buf ? one.buf : "",
|
||||||
SHA1_Update(&ctx, "\0", 1);
|
one.len + 1);
|
||||||
SHA1_Update(&ctx, two->ptr, two->nr);
|
SHA1_Update(&ctx, two.buf ? two.buf : "",
|
||||||
SHA1_Update(&ctx, "\0", 1);
|
two.len + 1);
|
||||||
}
|
}
|
||||||
clear_buffer(one);
|
strbuf_reset(&one);
|
||||||
clear_buffer(two);
|
strbuf_reset(&two);
|
||||||
} else if (hunk == 1)
|
} else if (hunk == 1)
|
||||||
append_line(one, buf);
|
strbuf_addstr(&one, buf);
|
||||||
else if (hunk == 2)
|
else if (hunk == 2)
|
||||||
append_line(two, buf);
|
strbuf_addstr(&two, buf);
|
||||||
else if (out)
|
else if (out)
|
||||||
fputs(buf, out);
|
fputs(buf, out);
|
||||||
}
|
}
|
||||||
|
strbuf_release(&one);
|
||||||
|
strbuf_release(&two);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if (out)
|
if (out)
|
||||||
|
@ -80,13 +80,13 @@ static void show_commit(struct commit *commit)
|
|||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
|
||||||
if (revs.verbose_header) {
|
if (revs.verbose_header) {
|
||||||
char *buf = NULL;
|
struct strbuf buf;
|
||||||
unsigned long buflen = 0;
|
strbuf_init(&buf, 0);
|
||||||
pretty_print_commit(revs.commit_format, commit, ~0,
|
pretty_print_commit(revs.commit_format, commit,
|
||||||
&buf, &buflen,
|
&buf, revs.abbrev, NULL, NULL, revs.date_mode);
|
||||||
revs.abbrev, NULL, NULL, revs.date_mode);
|
if (buf.len)
|
||||||
printf("%s%c", buf, hdr_termination);
|
printf("%s%c", buf.buf, hdr_termination);
|
||||||
free(buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
maybe_flush_or_die(stdout, "stdout");
|
maybe_flush_or_die(stdout, "stdout");
|
||||||
if (commit->parents) {
|
if (commit->parents) {
|
||||||
@ -436,10 +436,10 @@ static struct commit_list *find_bisection(struct commit_list *list,
|
|||||||
/* Do the real work of finding bisection commit. */
|
/* Do the real work of finding bisection commit. */
|
||||||
best = do_find_bisection(list, nr, weights);
|
best = do_find_bisection(list, nr, weights);
|
||||||
|
|
||||||
if (best)
|
if (best) {
|
||||||
best->next = NULL;
|
best->next = NULL;
|
||||||
|
|
||||||
*reaches = weight(best);
|
*reaches = weight(best);
|
||||||
|
}
|
||||||
free(weights);
|
free(weights);
|
||||||
|
|
||||||
return best;
|
return best;
|
||||||
|
@ -168,9 +168,7 @@ static void set_author_ident_env(const char *message)
|
|||||||
char *line, *pend, *email, *timestamp;
|
char *line, *pend, *email, *timestamp;
|
||||||
|
|
||||||
p += 7;
|
p += 7;
|
||||||
line = xmalloc(eol + 1 - p);
|
line = xmemdupz(p, eol - p);
|
||||||
memcpy(line, p, eol - p);
|
|
||||||
line[eol - p] = '\0';
|
|
||||||
email = strchr(line, '<');
|
email = strchr(line, '<');
|
||||||
if (!email)
|
if (!email)
|
||||||
die ("Could not extract author email from %s",
|
die ("Could not extract author email from %s",
|
||||||
|
@ -39,10 +39,7 @@ static void insert_author_oneline(struct path_list *list,
|
|||||||
while (authorlen > 0 && isspace(author[authorlen - 1]))
|
while (authorlen > 0 && isspace(author[authorlen - 1]))
|
||||||
authorlen--;
|
authorlen--;
|
||||||
|
|
||||||
buffer = xmalloc(authorlen + 1);
|
buffer = xmemdupz(author, authorlen);
|
||||||
memcpy(buffer, author, authorlen);
|
|
||||||
buffer[authorlen] = '\0';
|
|
||||||
|
|
||||||
item = path_list_insert(buffer, list);
|
item = path_list_insert(buffer, list);
|
||||||
if (item->util == NULL)
|
if (item->util == NULL)
|
||||||
item->util = xcalloc(1, sizeof(struct path_list));
|
item->util = xcalloc(1, sizeof(struct path_list));
|
||||||
@ -66,13 +63,9 @@ static void insert_author_oneline(struct path_list *list,
|
|||||||
oneline++;
|
oneline++;
|
||||||
onelinelen--;
|
onelinelen--;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (onelinelen > 0 && isspace(oneline[onelinelen - 1]))
|
while (onelinelen > 0 && isspace(oneline[onelinelen - 1]))
|
||||||
onelinelen--;
|
onelinelen--;
|
||||||
|
buffer = xmemdupz(oneline, onelinelen);
|
||||||
buffer = xmalloc(onelinelen + 1);
|
|
||||||
memcpy(buffer, oneline, onelinelen);
|
|
||||||
buffer[onelinelen] = '\0';
|
|
||||||
|
|
||||||
if (dot3) {
|
if (dot3) {
|
||||||
int dot3len = strlen(dot3);
|
int dot3len = strlen(dot3);
|
||||||
|
@ -259,16 +259,15 @@ static void join_revs(struct commit_list **list_p,
|
|||||||
|
|
||||||
static void show_one_commit(struct commit *commit, int no_name)
|
static void show_one_commit(struct commit *commit, int no_name)
|
||||||
{
|
{
|
||||||
char *pretty = NULL;
|
struct strbuf pretty;
|
||||||
const char *pretty_str = "(unavailable)";
|
const char *pretty_str = "(unavailable)";
|
||||||
unsigned long pretty_len = 0;
|
|
||||||
struct commit_name *name = commit->util;
|
struct commit_name *name = commit->util;
|
||||||
|
|
||||||
|
strbuf_init(&pretty, 0);
|
||||||
if (commit->object.parsed) {
|
if (commit->object.parsed) {
|
||||||
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
|
pretty_print_commit(CMIT_FMT_ONELINE, commit,
|
||||||
&pretty, &pretty_len,
|
&pretty, 0, NULL, NULL, 0);
|
||||||
0, NULL, NULL, 0);
|
pretty_str = pretty.buf;
|
||||||
pretty_str = pretty;
|
|
||||||
}
|
}
|
||||||
if (!prefixcmp(pretty_str, "[PATCH] "))
|
if (!prefixcmp(pretty_str, "[PATCH] "))
|
||||||
pretty_str += 8;
|
pretty_str += 8;
|
||||||
@ -289,7 +288,7 @@ static void show_one_commit(struct commit *commit, int no_name)
|
|||||||
find_unique_abbrev(commit->object.sha1, 7));
|
find_unique_abbrev(commit->object.sha1, 7));
|
||||||
}
|
}
|
||||||
puts(pretty_str);
|
puts(pretty_str);
|
||||||
free(pretty);
|
strbuf_release(&pretty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ref_name[MAX_REVS + 1];
|
static char *ref_name[MAX_REVS + 1];
|
||||||
|
@ -8,17 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
static size_t cleanup(char *line, size_t len)
|
static size_t cleanup(char *line, size_t len)
|
||||||
{
|
{
|
||||||
if (len) {
|
|
||||||
if (line[len - 1] == '\n')
|
|
||||||
len--;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned char c = line[len - 1];
|
unsigned char c = line[len - 1];
|
||||||
if (!isspace(c))
|
if (!isspace(c))
|
||||||
break;
|
break;
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,66 +30,60 @@ static size_t cleanup(char *line, size_t len)
|
|||||||
* If the input has only empty lines and spaces,
|
* If the input has only empty lines and spaces,
|
||||||
* no output will be produced.
|
* no output will be produced.
|
||||||
*
|
*
|
||||||
* If last line has a newline at the end, it will be removed.
|
* If last line does not have a newline at the end, one is added.
|
||||||
*
|
*
|
||||||
* Enable skip_comments to skip every line starting with "#".
|
* Enable skip_comments to skip every line starting with "#".
|
||||||
*/
|
*/
|
||||||
size_t stripspace(char *buffer, size_t length, int skip_comments)
|
void stripspace(struct strbuf *sb, int skip_comments)
|
||||||
{
|
{
|
||||||
int empties = -1;
|
int empties = 0;
|
||||||
size_t i, j, len, newlen;
|
size_t i, j, len, newlen;
|
||||||
char *eol;
|
char *eol;
|
||||||
|
|
||||||
for (i = j = 0; i < length; i += len, j += newlen) {
|
/* We may have to add a newline. */
|
||||||
eol = memchr(buffer + i, '\n', length - i);
|
strbuf_grow(sb, 1);
|
||||||
len = eol ? eol - (buffer + i) + 1 : length - i;
|
|
||||||
|
|
||||||
if (skip_comments && len && buffer[i] == '#') {
|
for (i = j = 0; i < sb->len; i += len, j += newlen) {
|
||||||
|
eol = memchr(sb->buf + i, '\n', sb->len - i);
|
||||||
|
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
|
||||||
|
|
||||||
|
if (skip_comments && len && sb->buf[i] == '#') {
|
||||||
newlen = 0;
|
newlen = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
newlen = cleanup(buffer + i, len);
|
newlen = cleanup(sb->buf + i, len);
|
||||||
|
|
||||||
/* Not just an empty line? */
|
/* Not just an empty line? */
|
||||||
if (newlen) {
|
if (newlen) {
|
||||||
if (empties != -1)
|
if (empties > 0 && j > 0)
|
||||||
buffer[j++] = '\n';
|
sb->buf[j++] = '\n';
|
||||||
if (empties > 0)
|
|
||||||
buffer[j++] = '\n';
|
|
||||||
empties = 0;
|
empties = 0;
|
||||||
memmove(buffer + j, buffer + i, newlen);
|
memmove(sb->buf + j, sb->buf + i, newlen);
|
||||||
continue;
|
sb->buf[newlen + j++] = '\n';
|
||||||
}
|
} else {
|
||||||
if (empties < 0)
|
|
||||||
continue;
|
|
||||||
empties++;
|
empties++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return j;
|
strbuf_setlen(sb, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_stripspace(int argc, const char **argv, const char *prefix)
|
int cmd_stripspace(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
char *buffer;
|
struct strbuf buf;
|
||||||
unsigned long size;
|
|
||||||
int strip_comments = 0;
|
int strip_comments = 0;
|
||||||
|
|
||||||
if (argc > 1 && (!strcmp(argv[1], "-s") ||
|
if (argc > 1 && (!strcmp(argv[1], "-s") ||
|
||||||
!strcmp(argv[1], "--strip-comments")))
|
!strcmp(argv[1], "--strip-comments")))
|
||||||
strip_comments = 1;
|
strip_comments = 1;
|
||||||
|
|
||||||
size = 1024;
|
strbuf_init(&buf, 0);
|
||||||
buffer = xmalloc(size);
|
if (strbuf_read(&buf, 0, 1024) < 0)
|
||||||
if (read_fd(0, &buffer, &size)) {
|
|
||||||
free(buffer);
|
|
||||||
die("could not read the input");
|
die("could not read the input");
|
||||||
}
|
|
||||||
|
|
||||||
size = stripspace(buffer, size, strip_comments);
|
stripspace(&buf, strip_comments);
|
||||||
write_or_die(1, buffer, size);
|
|
||||||
if (size)
|
|
||||||
putc('\n', stdout);
|
|
||||||
|
|
||||||
free(buffer);
|
write_or_die(1, buf.buf, buf.len);
|
||||||
|
strbuf_release(&buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,11 @@ static const char builtin_tag_usage[] =
|
|||||||
|
|
||||||
static char signingkey[1000];
|
static char signingkey[1000];
|
||||||
|
|
||||||
static void launch_editor(const char *path, char **buffer, unsigned long *len)
|
static void launch_editor(const char *path, struct strbuf *buffer)
|
||||||
{
|
{
|
||||||
const char *editor, *terminal;
|
const char *editor, *terminal;
|
||||||
struct child_process child;
|
struct child_process child;
|
||||||
const char *args[3];
|
const char *args[3];
|
||||||
int fd;
|
|
||||||
|
|
||||||
editor = getenv("GIT_EDITOR");
|
editor = getenv("GIT_EDITOR");
|
||||||
if (!editor && editor_program)
|
if (!editor && editor_program)
|
||||||
@ -52,15 +51,9 @@ static void launch_editor(const char *path, char **buffer, unsigned long *len)
|
|||||||
if (run_command(&child))
|
if (run_command(&child))
|
||||||
die("There was a problem with the editor %s.", editor);
|
die("There was a problem with the editor %s.", editor);
|
||||||
|
|
||||||
fd = open(path, O_RDONLY);
|
if (strbuf_read_file(buffer, path, 0) < 0)
|
||||||
if (fd < 0)
|
|
||||||
die("could not open '%s': %s", path, strerror(errno));
|
|
||||||
if (read_fd(fd, buffer, len)) {
|
|
||||||
free(*buffer);
|
|
||||||
die("could not read message file '%s': %s",
|
die("could not read message file '%s': %s",
|
||||||
path, strerror(errno));
|
path, strerror(errno));
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tag_filter {
|
struct tag_filter {
|
||||||
@ -184,7 +177,7 @@ static int verify_tag(const char *name, const char *ref,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t do_sign(char *buffer, size_t size, size_t max)
|
static int do_sign(struct strbuf *buffer)
|
||||||
{
|
{
|
||||||
struct child_process gpg;
|
struct child_process gpg;
|
||||||
const char *args[4];
|
const char *args[4];
|
||||||
@ -216,22 +209,22 @@ static ssize_t do_sign(char *buffer, size_t size, size_t max)
|
|||||||
if (start_command(&gpg))
|
if (start_command(&gpg))
|
||||||
return error("could not run gpg.");
|
return error("could not run gpg.");
|
||||||
|
|
||||||
if (write_in_full(gpg.in, buffer, size) != size) {
|
if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
|
||||||
close(gpg.in);
|
close(gpg.in);
|
||||||
finish_command(&gpg);
|
finish_command(&gpg);
|
||||||
return error("gpg did not accept the tag data");
|
return error("gpg did not accept the tag data");
|
||||||
}
|
}
|
||||||
close(gpg.in);
|
close(gpg.in);
|
||||||
gpg.close_in = 0;
|
gpg.close_in = 0;
|
||||||
len = read_in_full(gpg.out, buffer + size, max - size);
|
len = strbuf_read(buffer, gpg.out, 1024);
|
||||||
|
|
||||||
if (finish_command(&gpg) || !len || len < 0)
|
if (finish_command(&gpg) || !len || len < 0)
|
||||||
return error("gpg failed to sign the tag");
|
return error("gpg failed to sign the tag");
|
||||||
|
|
||||||
if (len == max - size)
|
if (len < 0)
|
||||||
return error("could not read the entire signature from gpg.");
|
return error("could not read the entire signature from gpg.");
|
||||||
|
|
||||||
return size + len;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char tag_template[] =
|
static const char tag_template[] =
|
||||||
@ -254,15 +247,13 @@ static int git_tag_config(const char *var, const char *value)
|
|||||||
return git_default_config(var, value);
|
return git_default_config(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_SIGNATURE_LENGTH 1024
|
|
||||||
/* message must be NULL or allocated, it will be reallocated and freed */
|
|
||||||
static void create_tag(const unsigned char *object, const char *tag,
|
static void create_tag(const unsigned char *object, const char *tag,
|
||||||
char *message, int sign, unsigned char *result)
|
struct strbuf *buf, int message, int sign,
|
||||||
|
unsigned char *result)
|
||||||
{
|
{
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
char header_buf[1024], *buffer = NULL;
|
char header_buf[1024];
|
||||||
int header_len, max_size;
|
int header_len;
|
||||||
unsigned long size = 0;
|
|
||||||
|
|
||||||
type = sha1_object_info(object, NULL);
|
type = sha1_object_info(object, NULL);
|
||||||
if (type <= OBJ_NONE)
|
if (type <= OBJ_NONE)
|
||||||
@ -294,53 +285,37 @@ static void create_tag(const unsigned char *object, const char *tag,
|
|||||||
write_or_die(fd, tag_template, strlen(tag_template));
|
write_or_die(fd, tag_template, strlen(tag_template));
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
launch_editor(path, &buffer, &size);
|
launch_editor(path, buf);
|
||||||
|
|
||||||
unlink(path);
|
unlink(path);
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
buffer = message;
|
|
||||||
size = strlen(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
size = stripspace(buffer, size, 1);
|
stripspace(buf, 1);
|
||||||
|
|
||||||
if (!message && !size)
|
if (!message && !buf->len)
|
||||||
die("no tag message?");
|
die("no tag message?");
|
||||||
|
|
||||||
/* insert the header and add the '\n' if needed: */
|
strbuf_insert(buf, 0, header_buf, header_len);
|
||||||
max_size = header_len + size + (sign ? MAX_SIGNATURE_LENGTH : 0) + 1;
|
|
||||||
buffer = xrealloc(buffer, max_size);
|
|
||||||
if (size)
|
|
||||||
buffer[size++] = '\n';
|
|
||||||
memmove(buffer + header_len, buffer, size);
|
|
||||||
memcpy(buffer, header_buf, header_len);
|
|
||||||
size += header_len;
|
|
||||||
|
|
||||||
if (sign) {
|
if (sign && do_sign(buf) < 0)
|
||||||
ssize_t r = do_sign(buffer, size, max_size);
|
|
||||||
if (r < 0)
|
|
||||||
die("unable to sign the tag");
|
die("unable to sign the tag");
|
||||||
size = r;
|
if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
|
||||||
}
|
|
||||||
|
|
||||||
if (write_sha1_file(buffer, size, tag_type, result) < 0)
|
|
||||||
die("unable to write tag file");
|
die("unable to write tag file");
|
||||||
free(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_tag(int argc, const char **argv, const char *prefix)
|
int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
|
struct strbuf buf;
|
||||||
unsigned char object[20], prev[20];
|
unsigned char object[20], prev[20];
|
||||||
int annotate = 0, sign = 0, force = 0, lines = 0;
|
int annotate = 0, sign = 0, force = 0, lines = 0, message = 0;
|
||||||
char *message = NULL;
|
|
||||||
char ref[PATH_MAX];
|
char ref[PATH_MAX];
|
||||||
const char *object_ref, *tag;
|
const char *object_ref, *tag;
|
||||||
int i;
|
int i;
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
|
|
||||||
git_config(git_tag_config);
|
git_config(git_tag_config);
|
||||||
|
strbuf_init(&buf, 0);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
@ -376,13 +351,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||||||
die("option -m needs an argument.");
|
die("option -m needs an argument.");
|
||||||
if (message)
|
if (message)
|
||||||
die("only one -F or -m option is allowed.");
|
die("only one -F or -m option is allowed.");
|
||||||
message = xstrdup(argv[i]);
|
strbuf_addstr(&buf, argv[i]);
|
||||||
|
message = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "-F")) {
|
if (!strcmp(arg, "-F")) {
|
||||||
unsigned long len;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
annotate = 1;
|
annotate = 1;
|
||||||
i++;
|
i++;
|
||||||
if (i == argc)
|
if (i == argc)
|
||||||
@ -390,20 +363,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||||||
if (message)
|
if (message)
|
||||||
die("only one -F or -m option is allowed.");
|
die("only one -F or -m option is allowed.");
|
||||||
|
|
||||||
if (!strcmp(argv[i], "-"))
|
if (!strcmp(argv[i], "-")) {
|
||||||
fd = 0;
|
if (strbuf_read(&buf, 0, 1024) < 0)
|
||||||
else {
|
die("cannot read %s", argv[i]);
|
||||||
fd = open(argv[i], O_RDONLY);
|
} else {
|
||||||
if (fd < 0)
|
if (strbuf_read_file(&buf, argv[i], 1024) < 0)
|
||||||
die("could not open '%s': %s",
|
die("could not open or read '%s': %s",
|
||||||
argv[i], strerror(errno));
|
argv[i], strerror(errno));
|
||||||
}
|
}
|
||||||
len = 1024;
|
message = 1;
|
||||||
message = xmalloc(len);
|
|
||||||
if (read_fd(fd, &message, &len)) {
|
|
||||||
free(message);
|
|
||||||
die("cannot read %s", argv[i]);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "-u")) {
|
if (!strcmp(arg, "-u")) {
|
||||||
@ -451,7 +419,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||||||
die("tag '%s' already exists", tag);
|
die("tag '%s' already exists", tag);
|
||||||
|
|
||||||
if (annotate)
|
if (annotate)
|
||||||
create_tag(object, tag, message, sign, object);
|
create_tag(object, tag, &buf, message, sign, object);
|
||||||
|
|
||||||
lock = lock_any_ref_for_update(ref, prev, 0);
|
lock = lock_any_ref_for_update(ref, prev, 0);
|
||||||
if (!lock)
|
if (!lock)
|
||||||
@ -459,5 +427,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||||||
if (write_ref_sha1(lock, object, NULL) < 0)
|
if (write_ref_sha1(lock, object, NULL) < 0)
|
||||||
die("%s: cannot update the ref", ref);
|
die("%s: cannot update the ref", ref);
|
||||||
|
|
||||||
|
strbuf_release(&buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
* Copyright (C) Linus Torvalds, 2005
|
* Copyright (C) Linus Torvalds, 2005
|
||||||
*/
|
*/
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "strbuf.h"
|
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
#include "tree-walk.h"
|
#include "tree-walk.h"
|
||||||
@ -296,8 +295,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
|
|||||||
static void read_index_info(int line_termination)
|
static void read_index_info(int line_termination)
|
||||||
{
|
{
|
||||||
struct strbuf buf;
|
struct strbuf buf;
|
||||||
strbuf_init(&buf);
|
struct strbuf uq;
|
||||||
while (1) {
|
|
||||||
|
strbuf_init(&buf, 0);
|
||||||
|
strbuf_init(&uq, 0);
|
||||||
|
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
|
||||||
char *ptr, *tab;
|
char *ptr, *tab;
|
||||||
char *path_name;
|
char *path_name;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
@ -321,10 +323,6 @@ static void read_index_info(int line_termination)
|
|||||||
* This format is to put higher order stages into the
|
* This format is to put higher order stages into the
|
||||||
* index file and matches git-ls-files --stage output.
|
* index file and matches git-ls-files --stage output.
|
||||||
*/
|
*/
|
||||||
read_line(&buf, stdin, line_termination);
|
|
||||||
if (buf.eof)
|
|
||||||
break;
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ul = strtoul(buf.buf, &ptr, 8);
|
ul = strtoul(buf.buf, &ptr, 8);
|
||||||
if (ptr == buf.buf || *ptr != ' '
|
if (ptr == buf.buf || *ptr != ' '
|
||||||
@ -349,15 +347,17 @@ static void read_index_info(int line_termination)
|
|||||||
if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
|
if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
|
||||||
goto bad_line;
|
goto bad_line;
|
||||||
|
|
||||||
if (line_termination && ptr[0] == '"')
|
|
||||||
path_name = unquote_c_style(ptr, NULL);
|
|
||||||
else
|
|
||||||
path_name = ptr;
|
path_name = ptr;
|
||||||
|
if (line_termination && path_name[0] == '"') {
|
||||||
|
strbuf_reset(&uq);
|
||||||
|
if (unquote_c_style(&uq, path_name, NULL)) {
|
||||||
|
die("git-update-index: bad quoting of path name");
|
||||||
|
}
|
||||||
|
path_name = uq.buf;
|
||||||
|
}
|
||||||
|
|
||||||
if (!verify_path(path_name)) {
|
if (!verify_path(path_name)) {
|
||||||
fprintf(stderr, "Ignoring path %s\n", path_name);
|
fprintf(stderr, "Ignoring path %s\n", path_name);
|
||||||
if (path_name != ptr)
|
|
||||||
free(path_name);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,13 +377,13 @@ static void read_index_info(int line_termination)
|
|||||||
die("git-update-index: unable to update %s",
|
die("git-update-index: unable to update %s",
|
||||||
path_name);
|
path_name);
|
||||||
}
|
}
|
||||||
if (path_name != ptr)
|
|
||||||
free(path_name);
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bad_line:
|
bad_line:
|
||||||
die("malformed index info %s", buf.buf);
|
die("malformed index info %s", buf.buf);
|
||||||
}
|
}
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&uq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char update_index_usage[] =
|
static const char update_index_usage[] =
|
||||||
@ -706,27 +706,27 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
|
|||||||
free((char*)p);
|
free((char*)p);
|
||||||
}
|
}
|
||||||
if (read_from_stdin) {
|
if (read_from_stdin) {
|
||||||
struct strbuf buf;
|
struct strbuf buf, nbuf;
|
||||||
strbuf_init(&buf);
|
|
||||||
while (1) {
|
strbuf_init(&buf, 0);
|
||||||
char *path_name;
|
strbuf_init(&nbuf, 0);
|
||||||
|
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
|
||||||
const char *p;
|
const char *p;
|
||||||
read_line(&buf, stdin, line_termination);
|
if (line_termination && buf.buf[0] == '"') {
|
||||||
if (buf.eof)
|
strbuf_reset(&nbuf);
|
||||||
break;
|
if (unquote_c_style(&nbuf, buf.buf, NULL))
|
||||||
if (line_termination && buf.buf[0] == '"')
|
die("line is badly quoted");
|
||||||
path_name = unquote_c_style(buf.buf, NULL);
|
strbuf_swap(&buf, &nbuf);
|
||||||
else
|
}
|
||||||
path_name = buf.buf;
|
p = prefix_path(prefix, prefix_length, buf.buf);
|
||||||
p = prefix_path(prefix, prefix_length, path_name);
|
|
||||||
update_one(p, NULL, 0);
|
update_one(p, NULL, 0);
|
||||||
if (set_executable_bit)
|
if (set_executable_bit)
|
||||||
chmod_path(set_executable_bit, p);
|
chmod_path(set_executable_bit, p);
|
||||||
if (p < path_name || p > path_name + strlen(path_name))
|
if (p < buf.buf || p > buf.buf + buf.len)
|
||||||
free((char*) p);
|
free((char *)p);
|
||||||
if (path_name != buf.buf)
|
|
||||||
free(path_name);
|
|
||||||
}
|
}
|
||||||
|
strbuf_release(&nbuf);
|
||||||
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
|
@ -7,7 +7,6 @@ extern const char git_version_string[];
|
|||||||
extern const char git_usage_string[];
|
extern const char git_usage_string[];
|
||||||
|
|
||||||
extern void help_unknown_cmd(const char *cmd);
|
extern void help_unknown_cmd(const char *cmd);
|
||||||
extern size_t stripspace(char *buffer, size_t length, int skip_comments);
|
|
||||||
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
||||||
extern void prune_packed_objects(int);
|
extern void prune_packed_objects(int);
|
||||||
|
|
||||||
|
60
cache-tree.c
60
cache-tree.c
@ -235,8 +235,7 @@ static int update_one(struct cache_tree *it,
|
|||||||
int missing_ok,
|
int missing_ok,
|
||||||
int dryrun)
|
int dryrun)
|
||||||
{
|
{
|
||||||
unsigned long size, offset;
|
struct strbuf buffer;
|
||||||
char *buffer;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (0 <= it->entry_count && has_sha1_file(it->sha1))
|
if (0 <= it->entry_count && has_sha1_file(it->sha1))
|
||||||
@ -293,9 +292,7 @@ static int update_one(struct cache_tree *it,
|
|||||||
/*
|
/*
|
||||||
* Then write out the tree object for this level.
|
* Then write out the tree object for this level.
|
||||||
*/
|
*/
|
||||||
size = 8192;
|
strbuf_init(&buffer, 8192);
|
||||||
buffer = xmalloc(size);
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < entries; i++) {
|
for (i = 0; i < entries; i++) {
|
||||||
struct cache_entry *ce = cache[i];
|
struct cache_entry *ce = cache[i];
|
||||||
@ -332,15 +329,9 @@ static int update_one(struct cache_tree *it,
|
|||||||
if (!ce->ce_mode)
|
if (!ce->ce_mode)
|
||||||
continue; /* entry being removed */
|
continue; /* entry being removed */
|
||||||
|
|
||||||
if (size < offset + entlen + 100) {
|
strbuf_grow(&buffer, entlen + 100);
|
||||||
size = alloc_nr(offset + entlen + 100);
|
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
|
||||||
buffer = xrealloc(buffer, size);
|
strbuf_add(&buffer, sha1, 20);
|
||||||
}
|
|
||||||
offset += sprintf(buffer + offset,
|
|
||||||
"%o %.*s", mode, entlen, path + baselen);
|
|
||||||
buffer[offset++] = 0;
|
|
||||||
hashcpy((unsigned char*)buffer + offset, sha1);
|
|
||||||
offset += 20;
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
fprintf(stderr, "cache-tree update-one %o %.*s\n",
|
fprintf(stderr, "cache-tree update-one %o %.*s\n",
|
||||||
@ -349,10 +340,10 @@ static int update_one(struct cache_tree *it,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dryrun)
|
if (dryrun)
|
||||||
hash_sha1_file(buffer, offset, tree_type, it->sha1);
|
hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
|
||||||
else
|
else
|
||||||
write_sha1_file(buffer, offset, tree_type, it->sha1);
|
write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
|
||||||
free(buffer);
|
strbuf_release(&buffer);
|
||||||
it->entry_count = i;
|
it->entry_count = i;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
|
fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
|
||||||
@ -378,12 +369,8 @@ int cache_tree_update(struct cache_tree *it,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *write_one(struct cache_tree *it,
|
static void write_one(struct strbuf *buffer, struct cache_tree *it,
|
||||||
char *path,
|
const char *path, int pathlen)
|
||||||
int pathlen,
|
|
||||||
char *buffer,
|
|
||||||
unsigned long *size,
|
|
||||||
unsigned long *offset)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -393,13 +380,9 @@ static void *write_one(struct cache_tree *it,
|
|||||||
* tree-sha1 (missing if invalid)
|
* tree-sha1 (missing if invalid)
|
||||||
* subtree_nr "cache-tree" entries for subtrees.
|
* subtree_nr "cache-tree" entries for subtrees.
|
||||||
*/
|
*/
|
||||||
if (*size < *offset + pathlen + 100) {
|
strbuf_grow(buffer, pathlen + 100);
|
||||||
*size = alloc_nr(*offset + pathlen + 100);
|
strbuf_add(buffer, path, pathlen);
|
||||||
buffer = xrealloc(buffer, *size);
|
strbuf_addf(buffer, "%c%d %d\n", 0, it->entry_count, it->subtree_nr);
|
||||||
}
|
|
||||||
*offset += sprintf(buffer + *offset, "%.*s%c%d %d\n",
|
|
||||||
pathlen, path, 0,
|
|
||||||
it->entry_count, it->subtree_nr);
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (0 <= it->entry_count)
|
if (0 <= it->entry_count)
|
||||||
@ -412,8 +395,7 @@ static void *write_one(struct cache_tree *it,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (0 <= it->entry_count) {
|
if (0 <= it->entry_count) {
|
||||||
hashcpy((unsigned char*)buffer + *offset, it->sha1);
|
strbuf_add(buffer, it->sha1, 20);
|
||||||
*offset += 20;
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < it->subtree_nr; i++) {
|
for (i = 0; i < it->subtree_nr; i++) {
|
||||||
struct cache_tree_sub *down = it->down[i];
|
struct cache_tree_sub *down = it->down[i];
|
||||||
@ -423,21 +405,13 @@ static void *write_one(struct cache_tree *it,
|
|||||||
prev->name, prev->namelen) <= 0)
|
prev->name, prev->namelen) <= 0)
|
||||||
die("fatal - unsorted cache subtree");
|
die("fatal - unsorted cache subtree");
|
||||||
}
|
}
|
||||||
buffer = write_one(down->cache_tree, down->name, down->namelen,
|
write_one(buffer, down->cache_tree, down->name, down->namelen);
|
||||||
buffer, size, offset);
|
|
||||||
}
|
}
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *cache_tree_write(struct cache_tree *root, unsigned long *size_p)
|
void cache_tree_write(struct strbuf *sb, struct cache_tree *root)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
write_one(sb, root, "", 0);
|
||||||
unsigned long size = 8192;
|
|
||||||
char *buffer = xmalloc(size);
|
|
||||||
|
|
||||||
*size_p = 0;
|
|
||||||
path[0] = 0;
|
|
||||||
return write_one(root, path, 0, buffer, &size, size_p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
|
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
|
||||||
|
@ -22,7 +22,7 @@ void cache_tree_free(struct cache_tree **);
|
|||||||
void cache_tree_invalidate_path(struct cache_tree *, const char *);
|
void cache_tree_invalidate_path(struct cache_tree *, const char *);
|
||||||
struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *);
|
struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *);
|
||||||
|
|
||||||
void *cache_tree_write(struct cache_tree *root, unsigned long *size_p);
|
void cache_tree_write(struct strbuf *, struct cache_tree *root);
|
||||||
struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
|
struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
|
||||||
|
|
||||||
int cache_tree_fully_valid(struct cache_tree *);
|
int cache_tree_fully_valid(struct cache_tree *);
|
||||||
|
11
cache.h
11
cache.h
@ -2,6 +2,7 @@
|
|||||||
#define CACHE_H
|
#define CACHE_H
|
||||||
|
|
||||||
#include "git-compat-util.h"
|
#include "git-compat-util.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
|
||||||
#include SHA1_HEADER
|
#include SHA1_HEADER
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@ -270,7 +271,6 @@ extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat
|
|||||||
extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
|
extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
|
||||||
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
||||||
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
|
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
|
||||||
extern int read_fd(int fd, char **return_buf, unsigned long *return_size);
|
|
||||||
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
|
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
|
||||||
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
|
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
|
||||||
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
||||||
@ -432,6 +432,7 @@ const char *show_date(unsigned long time, int timezone, enum date_mode mode);
|
|||||||
int parse_date(const char *date, char *buf, int bufsize);
|
int parse_date(const char *date, char *buf, int bufsize);
|
||||||
void datestamp(char *buf, int bufsize);
|
void datestamp(char *buf, int bufsize);
|
||||||
unsigned long approxidate(const char *);
|
unsigned long approxidate(const char *);
|
||||||
|
enum date_mode parse_date_format(const char *format);
|
||||||
|
|
||||||
extern const char *git_author_info(int);
|
extern const char *git_author_info(int);
|
||||||
extern const char *git_committer_info(int);
|
extern const char *git_committer_info(int);
|
||||||
@ -531,6 +532,7 @@ extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsign
|
|||||||
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
|
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
|
||||||
extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
|
extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
|
||||||
extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
|
extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
|
||||||
|
extern int matches_pack_name(struct packed_git *p, const char *name);
|
||||||
|
|
||||||
/* Dumb servers support */
|
/* Dumb servers support */
|
||||||
extern int update_server_info(int);
|
extern int update_server_info(int);
|
||||||
@ -586,14 +588,13 @@ extern void *alloc_object_node(void);
|
|||||||
extern void alloc_report(void);
|
extern void alloc_report(void);
|
||||||
|
|
||||||
/* trace.c */
|
/* trace.c */
|
||||||
extern int nfasprintf(char **str, const char *fmt, ...);
|
|
||||||
extern int nfvasprintf(char **str, const char *fmt, va_list va);
|
|
||||||
extern void trace_printf(const char *format, ...);
|
extern void trace_printf(const char *format, ...);
|
||||||
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
|
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
|
||||||
|
|
||||||
/* convert.c */
|
/* convert.c */
|
||||||
extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep);
|
/* returns 1 if *dst was used */
|
||||||
extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);
|
extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
|
||||||
|
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
|
||||||
|
|
||||||
/* diff.c */
|
/* diff.c */
|
||||||
extern int diff_auto_refresh_index;
|
extern int diff_auto_refresh_index;
|
||||||
|
@ -650,10 +650,7 @@ static void dump_quoted_path(const char *prefix, const char *path,
|
|||||||
const char *c_meta, const char *c_reset)
|
const char *c_meta, const char *c_reset)
|
||||||
{
|
{
|
||||||
printf("%s%s", c_meta, prefix);
|
printf("%s%s", c_meta, prefix);
|
||||||
if (quote_c_style(path, NULL, NULL, 0))
|
|
||||||
quote_c_style(path, NULL, stdout, 0);
|
quote_c_style(path, NULL, stdout, 0);
|
||||||
else
|
|
||||||
printf("%s", path);
|
|
||||||
printf("%s\n", c_reset);
|
printf("%s\n", c_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,16 +897,7 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
|
|||||||
putchar(inter_name_termination);
|
putchar(inter_name_termination);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_termination) {
|
write_name_quoted(p->path, stdout, line_termination);
|
||||||
if (quote_c_style(p->path, NULL, NULL, 0))
|
|
||||||
quote_c_style(p->path, NULL, stdout, 0);
|
|
||||||
else
|
|
||||||
printf("%s", p->path);
|
|
||||||
putchar(line_termination);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("%s%c", p->path, line_termination);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_combined_diff(struct combine_diff_path *p,
|
void show_combined_diff(struct combine_diff_path *p,
|
||||||
|
424
commit.c
424
commit.c
@ -441,28 +441,33 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
|
|||||||
|
|
||||||
void clear_commit_marks(struct commit *commit, unsigned int mark)
|
void clear_commit_marks(struct commit *commit, unsigned int mark)
|
||||||
{
|
{
|
||||||
|
while (commit) {
|
||||||
struct commit_list *parents;
|
struct commit_list *parents;
|
||||||
|
|
||||||
commit->object.flags &= ~mark;
|
if (!(mark & commit->object.flags))
|
||||||
parents = commit->parents;
|
return;
|
||||||
while (parents) {
|
|
||||||
struct commit *parent = parents->item;
|
|
||||||
|
|
||||||
/* Have we already cleared this? */
|
commit->object.flags &= ~mark;
|
||||||
if (mark & parent->object.flags)
|
|
||||||
clear_commit_marks(parent, mark);
|
parents = commit->parents;
|
||||||
parents = parents->next;
|
if (!parents)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((parents = parents->next))
|
||||||
|
clear_commit_marks(parents->item, mark);
|
||||||
|
|
||||||
|
commit = commit->parents->item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic support for pretty-printing the header
|
* Generic support for pretty-printing the header
|
||||||
*/
|
*/
|
||||||
static int get_one_line(const char *msg, unsigned long len)
|
static int get_one_line(const char *msg)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
while (len--) {
|
for (;;) {
|
||||||
char c = *msg++;
|
char c = *msg++;
|
||||||
if (!c)
|
if (!c)
|
||||||
break;
|
break;
|
||||||
@ -485,31 +490,25 @@ static int is_rfc2047_special(char ch)
|
|||||||
return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
|
return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_rfc2047(char *buf, const char *line, int len,
|
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
|
||||||
const char *encoding)
|
const char *encoding)
|
||||||
{
|
{
|
||||||
char *bp = buf;
|
int i, last;
|
||||||
int i, needquote;
|
|
||||||
char q_encoding[128];
|
|
||||||
const char *q_encoding_fmt = "=?%s?q?";
|
|
||||||
|
|
||||||
for (i = needquote = 0; !needquote && i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
int ch = line[i];
|
int ch = line[i];
|
||||||
if (non_ascii(ch))
|
if (non_ascii(ch))
|
||||||
needquote++;
|
goto needquote;
|
||||||
if ((i + 1 < len) &&
|
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
|
||||||
(ch == '=' && line[i+1] == '?'))
|
goto needquote;
|
||||||
needquote++;
|
|
||||||
}
|
}
|
||||||
if (!needquote)
|
strbuf_add(sb, line, len);
|
||||||
return sprintf(buf, "%.*s", len, line);
|
return;
|
||||||
|
|
||||||
i = snprintf(q_encoding, sizeof(q_encoding), q_encoding_fmt, encoding);
|
needquote:
|
||||||
if (sizeof(q_encoding) < i)
|
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
|
||||||
die("Insanely long encoding name %s", encoding);
|
strbuf_addf(sb, "=?%s?q?", encoding);
|
||||||
memcpy(bp, q_encoding, i);
|
for (i = last = 0; i < len; i++) {
|
||||||
bp += i;
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
unsigned ch = line[i] & 0xFF;
|
unsigned ch = line[i] & 0xFF;
|
||||||
/*
|
/*
|
||||||
* We encode ' ' using '=20' even though rfc2047
|
* We encode ' ' using '=20' even though rfc2047
|
||||||
@ -518,40 +517,30 @@ static int add_rfc2047(char *buf, const char *line, int len,
|
|||||||
* leave the underscore in place.
|
* leave the underscore in place.
|
||||||
*/
|
*/
|
||||||
if (is_rfc2047_special(ch) || ch == ' ') {
|
if (is_rfc2047_special(ch) || ch == ' ') {
|
||||||
sprintf(bp, "=%02X", ch);
|
strbuf_add(sb, line + last, i - last);
|
||||||
bp += 3;
|
strbuf_addf(sb, "=%02X", ch);
|
||||||
|
last = i + 1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
*bp++ = ch;
|
|
||||||
}
|
}
|
||||||
memcpy(bp, "?=", 2);
|
strbuf_add(sb, line + last, len - last);
|
||||||
bp += 2;
|
strbuf_addstr(sb, "?=");
|
||||||
return bp - buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long bound_rfc2047(unsigned long len, const char *encoding)
|
static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
|
||||||
{
|
|
||||||
/* upper bound of q encoded string of length 'len' */
|
|
||||||
unsigned long elen = strlen(encoding);
|
|
||||||
|
|
||||||
return len * 3 + elen + 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
|
|
||||||
const char *line, enum date_mode dmode,
|
const char *line, enum date_mode dmode,
|
||||||
const char *encoding)
|
const char *encoding)
|
||||||
{
|
{
|
||||||
char *date;
|
char *date;
|
||||||
int namelen;
|
int namelen;
|
||||||
unsigned long time;
|
unsigned long time;
|
||||||
int tz, ret;
|
int tz;
|
||||||
const char *filler = " ";
|
const char *filler = " ";
|
||||||
|
|
||||||
if (fmt == CMIT_FMT_ONELINE)
|
if (fmt == CMIT_FMT_ONELINE)
|
||||||
return 0;
|
return;
|
||||||
date = strchr(line, '>');
|
date = strchr(line, '>');
|
||||||
if (!date)
|
if (!date)
|
||||||
return 0;
|
return;
|
||||||
namelen = ++date - line;
|
namelen = ++date - line;
|
||||||
time = strtoul(date, &date, 10);
|
time = strtoul(date, &date, 10);
|
||||||
tz = strtol(date, NULL, 10);
|
tz = strtol(date, NULL, 10);
|
||||||
@ -560,42 +549,34 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
|
|||||||
char *name_tail = strchr(line, '<');
|
char *name_tail = strchr(line, '<');
|
||||||
int display_name_length;
|
int display_name_length;
|
||||||
if (!name_tail)
|
if (!name_tail)
|
||||||
return 0;
|
return;
|
||||||
while (line < name_tail && isspace(name_tail[-1]))
|
while (line < name_tail && isspace(name_tail[-1]))
|
||||||
name_tail--;
|
name_tail--;
|
||||||
display_name_length = name_tail - line;
|
display_name_length = name_tail - line;
|
||||||
filler = "";
|
filler = "";
|
||||||
strcpy(buf, "From: ");
|
strbuf_addstr(sb, "From: ");
|
||||||
ret = strlen(buf);
|
add_rfc2047(sb, line, display_name_length, encoding);
|
||||||
ret += add_rfc2047(buf + ret, line, display_name_length,
|
strbuf_add(sb, name_tail, namelen - display_name_length);
|
||||||
encoding);
|
strbuf_addch(sb, '\n');
|
||||||
memcpy(buf + ret, name_tail, namelen - display_name_length);
|
} else {
|
||||||
ret += namelen - display_name_length;
|
strbuf_addf(sb, "%s: %.*s%.*s\n", what,
|
||||||
buf[ret++] = '\n';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ret = sprintf(buf, "%s: %.*s%.*s\n", what,
|
|
||||||
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
|
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
|
||||||
filler, namelen, line);
|
filler, namelen, line);
|
||||||
}
|
}
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case CMIT_FMT_MEDIUM:
|
case CMIT_FMT_MEDIUM:
|
||||||
ret += sprintf(buf + ret, "Date: %s\n",
|
strbuf_addf(sb, "Date: %s\n", show_date(time, tz, dmode));
|
||||||
show_date(time, tz, dmode));
|
|
||||||
break;
|
break;
|
||||||
case CMIT_FMT_EMAIL:
|
case CMIT_FMT_EMAIL:
|
||||||
ret += sprintf(buf + ret, "Date: %s\n",
|
strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
|
||||||
show_date(time, tz, DATE_RFC2822));
|
|
||||||
break;
|
break;
|
||||||
case CMIT_FMT_FULLER:
|
case CMIT_FMT_FULLER:
|
||||||
ret += sprintf(buf + ret, "%sDate: %s\n", what,
|
strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
|
||||||
show_date(time, tz, dmode));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* notin' */
|
/* notin' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_empty_line(const char *line, int *len_p)
|
static int is_empty_line(const char *line, int *len_p)
|
||||||
@ -607,16 +588,16 @@ static int is_empty_line(const char *line, int *len_p)
|
|||||||
return !len;
|
return !len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *commit, int abbrev)
|
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
|
||||||
|
const struct commit *commit, int abbrev)
|
||||||
{
|
{
|
||||||
struct commit_list *parent = commit->parents;
|
struct commit_list *parent = commit->parents;
|
||||||
int offset;
|
|
||||||
|
|
||||||
if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
|
if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
|
||||||
!parent || !parent->next)
|
!parent || !parent->next)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
offset = sprintf(buf, "Merge:");
|
strbuf_addstr(sb, "Merge:");
|
||||||
|
|
||||||
while (parent) {
|
while (parent) {
|
||||||
struct commit *p = parent->item;
|
struct commit *p = parent->item;
|
||||||
@ -629,10 +610,9 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com
|
|||||||
dots = (abbrev && strlen(hex) != 40) ? "..." : "";
|
dots = (abbrev && strlen(hex) != 40) ? "..." : "";
|
||||||
parent = parent->next;
|
parent = parent->next;
|
||||||
|
|
||||||
offset += sprintf(buf + offset, " %s%s", hex, dots);
|
strbuf_addf(sb, " %s%s", hex, dots);
|
||||||
}
|
}
|
||||||
buf[offset++] = '\n';
|
strbuf_addch(sb, '\n');
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_header(const struct commit *commit, const char *key)
|
static char *get_header(const struct commit *commit, const char *key)
|
||||||
@ -653,11 +633,7 @@ static char *get_header(const struct commit *commit, const char *key)
|
|||||||
if (eol - line > key_len &&
|
if (eol - line > key_len &&
|
||||||
!strncmp(line, key, key_len) &&
|
!strncmp(line, key, key_len) &&
|
||||||
line[key_len] == ' ') {
|
line[key_len] == ' ') {
|
||||||
int len = eol - line - key_len;
|
return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
|
||||||
char *ret = xmalloc(len);
|
|
||||||
memcpy(ret, line + key_len + 1, len - 1);
|
|
||||||
ret[len - 1] = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
@ -665,47 +641,34 @@ static char *get_header(const struct commit *commit, const char *key)
|
|||||||
|
|
||||||
static char *replace_encoding_header(char *buf, const char *encoding)
|
static char *replace_encoding_header(char *buf, const char *encoding)
|
||||||
{
|
{
|
||||||
char *encoding_header = strstr(buf, "\nencoding ");
|
struct strbuf tmp;
|
||||||
char *header_end = strstr(buf, "\n\n");
|
size_t start, len;
|
||||||
char *end_of_encoding_header;
|
char *cp = buf;
|
||||||
int encoding_header_pos;
|
|
||||||
int encoding_header_len;
|
|
||||||
int new_len;
|
|
||||||
int need_len;
|
|
||||||
int buflen = strlen(buf) + 1;
|
|
||||||
|
|
||||||
if (!header_end)
|
/* guess if there is an encoding header before a \n\n */
|
||||||
header_end = buf + buflen;
|
while (strncmp(cp, "encoding ", strlen("encoding "))) {
|
||||||
if (!encoding_header || encoding_header >= header_end)
|
cp = strchr(cp, '\n');
|
||||||
|
if (!cp || *++cp == '\n')
|
||||||
return buf;
|
return buf;
|
||||||
encoding_header++;
|
}
|
||||||
end_of_encoding_header = strchr(encoding_header, '\n');
|
start = cp - buf;
|
||||||
if (!end_of_encoding_header)
|
cp = strchr(cp, '\n');
|
||||||
|
if (!cp)
|
||||||
return buf; /* should not happen but be defensive */
|
return buf; /* should not happen but be defensive */
|
||||||
end_of_encoding_header++;
|
len = cp + 1 - (buf + start);
|
||||||
|
|
||||||
encoding_header_len = end_of_encoding_header - encoding_header;
|
|
||||||
encoding_header_pos = encoding_header - buf;
|
|
||||||
|
|
||||||
|
strbuf_init(&tmp, 0);
|
||||||
|
strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
|
||||||
if (is_encoding_utf8(encoding)) {
|
if (is_encoding_utf8(encoding)) {
|
||||||
/* we have re-coded to UTF-8; drop the header */
|
/* we have re-coded to UTF-8; drop the header */
|
||||||
memmove(encoding_header, end_of_encoding_header,
|
strbuf_remove(&tmp, start, len);
|
||||||
buflen - (encoding_header_pos + encoding_header_len));
|
} else {
|
||||||
return buf;
|
/* just replaces XXXX in 'encoding XXXX\n' */
|
||||||
|
strbuf_splice(&tmp, start + strlen("encoding "),
|
||||||
|
len - strlen("encoding \n"),
|
||||||
|
encoding, strlen(encoding));
|
||||||
}
|
}
|
||||||
new_len = strlen(encoding);
|
return strbuf_detach(&tmp, NULL);
|
||||||
need_len = new_len + strlen("encoding \n");
|
|
||||||
if (encoding_header_len < need_len) {
|
|
||||||
buf = xrealloc(buf, buflen + (need_len - encoding_header_len));
|
|
||||||
encoding_header = buf + encoding_header_pos;
|
|
||||||
end_of_encoding_header = encoding_header + encoding_header_len;
|
|
||||||
}
|
|
||||||
memmove(end_of_encoding_header + (need_len - encoding_header_len),
|
|
||||||
end_of_encoding_header,
|
|
||||||
buflen - (encoding_header_pos + encoding_header_len));
|
|
||||||
memcpy(encoding_header + 9, encoding, strlen(encoding));
|
|
||||||
encoding_header[9 + new_len] = '\n';
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *logmsg_reencode(const struct commit *commit,
|
static char *logmsg_reencode(const struct commit *commit,
|
||||||
@ -747,7 +710,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
|
|||||||
start = end + 1;
|
start = end + 1;
|
||||||
while (end > 0 && isspace(msg[end - 1]))
|
while (end > 0 && isspace(msg[end - 1]))
|
||||||
end--;
|
end--;
|
||||||
table[0].value = xstrndup(msg, end);
|
table[0].value = xmemdupz(msg, end);
|
||||||
|
|
||||||
if (start >= len)
|
if (start >= len)
|
||||||
return;
|
return;
|
||||||
@ -759,7 +722,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
|
|||||||
if (end >= len)
|
if (end >= len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
table[1].value = xstrndup(msg + start, end - start);
|
table[1].value = xmemdupz(msg + start, end - start);
|
||||||
|
|
||||||
/* parse date */
|
/* parse date */
|
||||||
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
||||||
@ -770,7 +733,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
|
|||||||
if (msg + start == ep)
|
if (msg + start == ep)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
table[5].value = xstrndup(msg + start, ep - (msg + start));
|
table[5].value = xmemdupz(msg + start, ep - (msg + start));
|
||||||
|
|
||||||
/* parse tz */
|
/* parse tz */
|
||||||
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
|
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
|
||||||
@ -787,8 +750,8 @@ static void fill_person(struct interp *table, const char *msg, int len)
|
|||||||
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
|
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
|
||||||
}
|
}
|
||||||
|
|
||||||
long format_commit_message(const struct commit *commit, const void *format,
|
void format_commit_message(const struct commit *commit,
|
||||||
char **buf_p, unsigned long *space_p)
|
const void *format, struct strbuf *sb)
|
||||||
{
|
{
|
||||||
struct interp table[] = {
|
struct interp table[] = {
|
||||||
{ "%H" }, /* commit hash */
|
{ "%H" }, /* commit hash */
|
||||||
@ -841,6 +804,7 @@ long format_commit_message(const struct commit *commit, const void *format,
|
|||||||
};
|
};
|
||||||
struct commit_list *p;
|
struct commit_list *p;
|
||||||
char parents[1024];
|
char parents[1024];
|
||||||
|
unsigned long len;
|
||||||
int i;
|
int i;
|
||||||
enum { HEADER, SUBJECT, BODY } state;
|
enum { HEADER, SUBJECT, BODY } state;
|
||||||
const char *msg = commit->buffer;
|
const char *msg = commit->buffer;
|
||||||
@ -896,7 +860,7 @@ long format_commit_message(const struct commit *commit, const void *format,
|
|||||||
; /* do nothing */
|
; /* do nothing */
|
||||||
|
|
||||||
if (state == SUBJECT) {
|
if (state == SUBJECT) {
|
||||||
table[ISUBJECT].value = xstrndup(msg + i, eol - i);
|
table[ISUBJECT].value = xmemdupz(msg + i, eol - i);
|
||||||
i = eol;
|
i = eol;
|
||||||
}
|
}
|
||||||
if (i == eol) {
|
if (i == eol) {
|
||||||
@ -912,30 +876,21 @@ long format_commit_message(const struct commit *commit, const void *format,
|
|||||||
msg + i + 10, eol - i - 10);
|
msg + i + 10, eol - i - 10);
|
||||||
else if (!prefixcmp(msg + i, "encoding "))
|
else if (!prefixcmp(msg + i, "encoding "))
|
||||||
table[IENCODING].value =
|
table[IENCODING].value =
|
||||||
xstrndup(msg + i + 9, eol - i - 9);
|
xmemdupz(msg + i + 9, eol - i - 9);
|
||||||
i = eol;
|
i = eol;
|
||||||
}
|
}
|
||||||
if (msg[i])
|
if (msg[i])
|
||||||
table[IBODY].value = xstrdup(msg + i);
|
table[IBODY].value = xstrdup(msg + i);
|
||||||
for (i = 0; i < ARRAY_SIZE(table); i++)
|
|
||||||
if (!table[i].value)
|
|
||||||
interp_set_entry(table, i, "<unknown>");
|
|
||||||
|
|
||||||
do {
|
len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
|
||||||
char *buf = *buf_p;
|
format, table, ARRAY_SIZE(table));
|
||||||
unsigned long space = *space_p;
|
if (len > strbuf_avail(sb)) {
|
||||||
|
strbuf_grow(sb, len);
|
||||||
space = interpolate(buf, space, format,
|
interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
|
||||||
table, ARRAY_SIZE(table));
|
format, table, ARRAY_SIZE(table));
|
||||||
if (!space)
|
}
|
||||||
break;
|
strbuf_setlen(sb, sb->len + len);
|
||||||
buf = xrealloc(buf, space);
|
|
||||||
*buf_p = buf;
|
|
||||||
*space_p = space;
|
|
||||||
} while (1);
|
|
||||||
interp_clear_table(table, ARRAY_SIZE(table));
|
interp_clear_table(table, ARRAY_SIZE(table));
|
||||||
|
|
||||||
return strlen(*buf_p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pp_header(enum cmit_fmt fmt,
|
static void pp_header(enum cmit_fmt fmt,
|
||||||
@ -944,34 +899,24 @@ static void pp_header(enum cmit_fmt fmt,
|
|||||||
const char *encoding,
|
const char *encoding,
|
||||||
const struct commit *commit,
|
const struct commit *commit,
|
||||||
const char **msg_p,
|
const char **msg_p,
|
||||||
unsigned long *len_p,
|
struct strbuf *sb)
|
||||||
unsigned long *ofs_p,
|
|
||||||
char **buf_p,
|
|
||||||
unsigned long *space_p)
|
|
||||||
{
|
{
|
||||||
int parents_shown = 0;
|
int parents_shown = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *line = *msg_p;
|
const char *line = *msg_p;
|
||||||
char *dst;
|
int linelen = get_one_line(*msg_p);
|
||||||
int linelen = get_one_line(*msg_p, *len_p);
|
|
||||||
unsigned long len;
|
|
||||||
|
|
||||||
if (!linelen)
|
if (!linelen)
|
||||||
return;
|
return;
|
||||||
*msg_p += linelen;
|
*msg_p += linelen;
|
||||||
*len_p -= linelen;
|
|
||||||
|
|
||||||
if (linelen == 1)
|
if (linelen == 1)
|
||||||
/* End of header */
|
/* End of header */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p);
|
|
||||||
dst = *buf_p + *ofs_p;
|
|
||||||
|
|
||||||
if (fmt == CMIT_FMT_RAW) {
|
if (fmt == CMIT_FMT_RAW) {
|
||||||
memcpy(dst, line, linelen);
|
strbuf_add(sb, line, linelen);
|
||||||
*ofs_p += linelen;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,10 +934,8 @@ static void pp_header(enum cmit_fmt fmt,
|
|||||||
parent = parent->next, num++)
|
parent = parent->next, num++)
|
||||||
;
|
;
|
||||||
/* with enough slop */
|
/* with enough slop */
|
||||||
num = *ofs_p + num * 50 + 20;
|
strbuf_grow(sb, num * 50 + 20);
|
||||||
ALLOC_GROW(*buf_p, num, *space_p);
|
add_merge_info(fmt, sb, commit, abbrev);
|
||||||
dst = *buf_p + *ofs_p;
|
|
||||||
*ofs_p += add_merge_info(fmt, dst, commit, abbrev);
|
|
||||||
parents_shown = 1;
|
parents_shown = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,129 +945,82 @@ static void pp_header(enum cmit_fmt fmt,
|
|||||||
* FULLER shows both authors and dates.
|
* FULLER shows both authors and dates.
|
||||||
*/
|
*/
|
||||||
if (!memcmp(line, "author ", 7)) {
|
if (!memcmp(line, "author ", 7)) {
|
||||||
len = linelen;
|
strbuf_grow(sb, linelen + 80);
|
||||||
if (fmt == CMIT_FMT_EMAIL)
|
add_user_info("Author", fmt, sb, line + 7, dmode, encoding);
|
||||||
len = bound_rfc2047(linelen, encoding);
|
|
||||||
ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
|
|
||||||
dst = *buf_p + *ofs_p;
|
|
||||||
*ofs_p += add_user_info("Author", fmt, dst,
|
|
||||||
line + 7, dmode, encoding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!memcmp(line, "committer ", 10) &&
|
if (!memcmp(line, "committer ", 10) &&
|
||||||
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
|
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
|
||||||
len = linelen;
|
strbuf_grow(sb, linelen + 80);
|
||||||
if (fmt == CMIT_FMT_EMAIL)
|
add_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
|
||||||
len = bound_rfc2047(linelen, encoding);
|
|
||||||
ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
|
|
||||||
dst = *buf_p + *ofs_p;
|
|
||||||
*ofs_p += add_user_info("Commit", fmt, dst,
|
|
||||||
line + 10, dmode, encoding);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pp_title_line(enum cmit_fmt fmt,
|
static void pp_title_line(enum cmit_fmt fmt,
|
||||||
const char **msg_p,
|
const char **msg_p,
|
||||||
unsigned long *len_p,
|
struct strbuf *sb,
|
||||||
unsigned long *ofs_p,
|
|
||||||
char **buf_p,
|
|
||||||
unsigned long *space_p,
|
|
||||||
int indent,
|
|
||||||
const char *subject,
|
const char *subject,
|
||||||
const char *after_subject,
|
const char *after_subject,
|
||||||
const char *encoding,
|
const char *encoding,
|
||||||
int plain_non_ascii)
|
int plain_non_ascii)
|
||||||
{
|
{
|
||||||
char *title;
|
struct strbuf title;
|
||||||
unsigned long title_alloc, title_len;
|
|
||||||
unsigned long len;
|
strbuf_init(&title, 80);
|
||||||
|
|
||||||
title_len = 0;
|
|
||||||
title_alloc = 80;
|
|
||||||
title = xmalloc(title_alloc);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *line = *msg_p;
|
const char *line = *msg_p;
|
||||||
int linelen = get_one_line(line, *len_p);
|
int linelen = get_one_line(line);
|
||||||
*msg_p += linelen;
|
|
||||||
*len_p -= linelen;
|
|
||||||
|
|
||||||
|
*msg_p += linelen;
|
||||||
if (!linelen || is_empty_line(line, &linelen))
|
if (!linelen || is_empty_line(line, &linelen))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (title_alloc <= title_len + linelen + 2) {
|
strbuf_grow(&title, linelen + 2);
|
||||||
title_alloc = title_len + linelen + 80;
|
if (title.len) {
|
||||||
title = xrealloc(title, title_alloc);
|
|
||||||
}
|
|
||||||
len = 0;
|
|
||||||
if (title_len) {
|
|
||||||
if (fmt == CMIT_FMT_EMAIL) {
|
if (fmt == CMIT_FMT_EMAIL) {
|
||||||
len++;
|
strbuf_addch(&title, '\n');
|
||||||
title[title_len++] = '\n';
|
|
||||||
}
|
}
|
||||||
len++;
|
strbuf_addch(&title, ' ');
|
||||||
title[title_len++] = ' ';
|
|
||||||
}
|
}
|
||||||
memcpy(title + title_len, line, linelen);
|
strbuf_add(&title, line, linelen);
|
||||||
title_len += linelen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enough slop for the MIME header and rfc2047 */
|
strbuf_grow(sb, title.len + 1024);
|
||||||
len = bound_rfc2047(title_len, encoding)+ 1000;
|
|
||||||
if (subject)
|
|
||||||
len += strlen(subject);
|
|
||||||
if (after_subject)
|
|
||||||
len += strlen(after_subject);
|
|
||||||
if (encoding)
|
|
||||||
len += strlen(encoding);
|
|
||||||
ALLOC_GROW(*buf_p, title_len + *ofs_p + len, *space_p);
|
|
||||||
|
|
||||||
if (subject) {
|
if (subject) {
|
||||||
len = strlen(subject);
|
strbuf_addstr(sb, subject);
|
||||||
memcpy(*buf_p + *ofs_p, subject, len);
|
add_rfc2047(sb, title.buf, title.len, encoding);
|
||||||
*ofs_p += len;
|
|
||||||
*ofs_p += add_rfc2047(*buf_p + *ofs_p,
|
|
||||||
title, title_len, encoding);
|
|
||||||
} else {
|
} else {
|
||||||
memcpy(*buf_p + *ofs_p, title, title_len);
|
strbuf_addbuf(sb, &title);
|
||||||
*ofs_p += title_len;
|
|
||||||
}
|
}
|
||||||
(*buf_p)[(*ofs_p)++] = '\n';
|
strbuf_addch(sb, '\n');
|
||||||
|
|
||||||
if (plain_non_ascii) {
|
if (plain_non_ascii) {
|
||||||
const char *header_fmt =
|
const char *header_fmt =
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=%s\n"
|
"Content-Type: text/plain; charset=%s\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n";
|
"Content-Transfer-Encoding: 8bit\n";
|
||||||
*ofs_p += snprintf(*buf_p + *ofs_p,
|
strbuf_addf(sb, header_fmt, encoding);
|
||||||
*space_p - *ofs_p,
|
|
||||||
header_fmt, encoding);
|
|
||||||
}
|
}
|
||||||
if (after_subject) {
|
if (after_subject) {
|
||||||
len = strlen(after_subject);
|
strbuf_addstr(sb, after_subject);
|
||||||
memcpy(*buf_p + *ofs_p, after_subject, len);
|
|
||||||
*ofs_p += len;
|
|
||||||
}
|
}
|
||||||
free(title);
|
|
||||||
if (fmt == CMIT_FMT_EMAIL) {
|
if (fmt == CMIT_FMT_EMAIL) {
|
||||||
ALLOC_GROW(*buf_p, *ofs_p + 20, *space_p);
|
strbuf_addch(sb, '\n');
|
||||||
(*buf_p)[(*ofs_p)++] = '\n';
|
|
||||||
}
|
}
|
||||||
|
strbuf_release(&title);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pp_remainder(enum cmit_fmt fmt,
|
static void pp_remainder(enum cmit_fmt fmt,
|
||||||
const char **msg_p,
|
const char **msg_p,
|
||||||
unsigned long *len_p,
|
struct strbuf *sb,
|
||||||
unsigned long *ofs_p,
|
|
||||||
char **buf_p,
|
|
||||||
unsigned long *space_p,
|
|
||||||
int indent)
|
int indent)
|
||||||
{
|
{
|
||||||
int first = 1;
|
int first = 1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *line = *msg_p;
|
const char *line = *msg_p;
|
||||||
int linelen = get_one_line(line, *len_p);
|
int linelen = get_one_line(line);
|
||||||
*msg_p += linelen;
|
*msg_p += linelen;
|
||||||
*len_p -= linelen;
|
|
||||||
|
|
||||||
if (!linelen)
|
if (!linelen)
|
||||||
break;
|
break;
|
||||||
@ -1137,36 +1033,32 @@ static void pp_remainder(enum cmit_fmt fmt,
|
|||||||
}
|
}
|
||||||
first = 0;
|
first = 0;
|
||||||
|
|
||||||
ALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p);
|
strbuf_grow(sb, linelen + indent + 20);
|
||||||
if (indent) {
|
if (indent) {
|
||||||
memset(*buf_p + *ofs_p, ' ', indent);
|
memset(sb->buf + sb->len, ' ', indent);
|
||||||
*ofs_p += indent;
|
strbuf_setlen(sb, sb->len + indent);
|
||||||
}
|
}
|
||||||
memcpy(*buf_p + *ofs_p, line, linelen);
|
strbuf_add(sb, line, linelen);
|
||||||
*ofs_p += linelen;
|
strbuf_addch(sb, '\n');
|
||||||
(*buf_p)[(*ofs_p)++] = '\n';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
|
||||||
const struct commit *commit,
|
struct strbuf *sb, int abbrev,
|
||||||
unsigned long len,
|
const char *subject, const char *after_subject,
|
||||||
char **buf_p, unsigned long *space_p,
|
|
||||||
int abbrev, const char *subject,
|
|
||||||
const char *after_subject,
|
|
||||||
enum date_mode dmode)
|
enum date_mode dmode)
|
||||||
{
|
{
|
||||||
unsigned long offset = 0;
|
|
||||||
unsigned long beginning_of_body;
|
unsigned long beginning_of_body;
|
||||||
int indent = 4;
|
int indent = 4;
|
||||||
const char *msg = commit->buffer;
|
const char *msg = commit->buffer;
|
||||||
int plain_non_ascii = 0;
|
int plain_non_ascii = 0;
|
||||||
char *reencoded;
|
char *reencoded;
|
||||||
const char *encoding;
|
const char *encoding;
|
||||||
char *buf;
|
|
||||||
|
|
||||||
if (fmt == CMIT_FMT_USERFORMAT)
|
if (fmt == CMIT_FMT_USERFORMAT) {
|
||||||
return format_commit_message(commit, user_format, buf_p, space_p);
|
format_commit_message(commit, user_format, sb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
encoding = (git_log_output_encoding
|
encoding = (git_log_output_encoding
|
||||||
? git_log_output_encoding
|
? git_log_output_encoding
|
||||||
@ -1176,7 +1068,6 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
|||||||
reencoded = logmsg_reencode(commit, encoding);
|
reencoded = logmsg_reencode(commit, encoding);
|
||||||
if (reencoded) {
|
if (reencoded) {
|
||||||
msg = reencoded;
|
msg = reencoded;
|
||||||
len = strlen(reencoded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||||
@ -1191,14 +1082,13 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
|||||||
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
|
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
|
||||||
int i, ch, in_body;
|
int i, ch, in_body;
|
||||||
|
|
||||||
for (in_body = i = 0; (ch = msg[i]) && i < len; i++) {
|
for (in_body = i = 0; (ch = msg[i]); i++) {
|
||||||
if (!in_body) {
|
if (!in_body) {
|
||||||
/* author could be non 7-bit ASCII but
|
/* author could be non 7-bit ASCII but
|
||||||
* the log may be so; skip over the
|
* the log may be so; skip over the
|
||||||
* header part first.
|
* header part first.
|
||||||
*/
|
*/
|
||||||
if (ch == '\n' &&
|
if (ch == '\n' && msg[i+1] == '\n')
|
||||||
i + 1 < len && msg[i+1] == '\n')
|
|
||||||
in_body = 1;
|
in_body = 1;
|
||||||
}
|
}
|
||||||
else if (non_ascii(ch)) {
|
else if (non_ascii(ch)) {
|
||||||
@ -1208,59 +1098,44 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pp_header(fmt, abbrev, dmode, encoding,
|
pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
|
||||||
commit, &msg, &len,
|
|
||||||
&offset, buf_p, space_p);
|
|
||||||
if (fmt != CMIT_FMT_ONELINE && !subject) {
|
if (fmt != CMIT_FMT_ONELINE && !subject) {
|
||||||
ALLOC_GROW(*buf_p, offset + 20, *space_p);
|
strbuf_addch(sb, '\n');
|
||||||
(*buf_p)[offset++] = '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip excess blank lines at the beginning of body, if any... */
|
/* Skip excess blank lines at the beginning of body, if any... */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int linelen = get_one_line(msg, len);
|
int linelen = get_one_line(msg);
|
||||||
int ll = linelen;
|
int ll = linelen;
|
||||||
if (!linelen)
|
if (!linelen)
|
||||||
break;
|
break;
|
||||||
if (!is_empty_line(msg, &ll))
|
if (!is_empty_line(msg, &ll))
|
||||||
break;
|
break;
|
||||||
msg += linelen;
|
msg += linelen;
|
||||||
len -= linelen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These formats treat the title line specially. */
|
/* These formats treat the title line specially. */
|
||||||
if (fmt == CMIT_FMT_ONELINE
|
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||||
|| fmt == CMIT_FMT_EMAIL)
|
pp_title_line(fmt, &msg, sb, subject,
|
||||||
pp_title_line(fmt, &msg, &len, &offset,
|
after_subject, encoding, plain_non_ascii);
|
||||||
buf_p, space_p, indent,
|
|
||||||
subject, after_subject, encoding,
|
|
||||||
plain_non_ascii);
|
|
||||||
|
|
||||||
beginning_of_body = offset;
|
beginning_of_body = sb->len;
|
||||||
if (fmt != CMIT_FMT_ONELINE)
|
if (fmt != CMIT_FMT_ONELINE)
|
||||||
pp_remainder(fmt, &msg, &len, &offset,
|
pp_remainder(fmt, &msg, sb, indent);
|
||||||
buf_p, space_p, indent);
|
strbuf_rtrim(sb);
|
||||||
|
|
||||||
while (offset && isspace((*buf_p)[offset-1]))
|
|
||||||
offset--;
|
|
||||||
|
|
||||||
ALLOC_GROW(*buf_p, offset + 20, *space_p);
|
|
||||||
buf = *buf_p;
|
|
||||||
|
|
||||||
/* Make sure there is an EOLN for the non-oneline case */
|
/* Make sure there is an EOLN for the non-oneline case */
|
||||||
if (fmt != CMIT_FMT_ONELINE)
|
if (fmt != CMIT_FMT_ONELINE)
|
||||||
buf[offset++] = '\n';
|
strbuf_addch(sb, '\n');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The caller may append additional body text in e-mail
|
* The caller may append additional body text in e-mail
|
||||||
* format. Make sure we did not strip the blank line
|
* format. Make sure we did not strip the blank line
|
||||||
* between the header and the body.
|
* between the header and the body.
|
||||||
*/
|
*/
|
||||||
if (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body)
|
if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
|
||||||
buf[offset++] = '\n';
|
strbuf_addch(sb, '\n');
|
||||||
buf[offset] = '\0';
|
|
||||||
free(reencoded);
|
free(reencoded);
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct commit *pop_commit(struct commit_list **stack)
|
struct commit *pop_commit(struct commit_list **stack)
|
||||||
@ -1483,8 +1358,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct commit_list *get_merge_bases(struct commit *one,
|
struct commit_list *get_merge_bases(struct commit *one,
|
||||||
struct commit *two,
|
struct commit *two, int cleanup)
|
||||||
int cleanup)
|
|
||||||
{
|
{
|
||||||
struct commit_list *list;
|
struct commit_list *list;
|
||||||
struct commit **rslt;
|
struct commit **rslt;
|
||||||
|
9
commit.h
9
commit.h
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "strbuf.h"
|
||||||
#include "decorate.h"
|
#include "decorate.h"
|
||||||
|
|
||||||
struct commit_list {
|
struct commit_list {
|
||||||
@ -61,8 +62,12 @@ enum cmit_fmt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern enum cmit_fmt get_commit_format(const char *arg);
|
extern enum cmit_fmt get_commit_format(const char *arg);
|
||||||
extern long format_commit_message(const struct commit *commit, const void *template, char **buf_p, unsigned long *space_p);
|
extern void format_commit_message(const struct commit *commit,
|
||||||
extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char **buf_p, unsigned long *space_p, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);
|
const void *format, struct strbuf *sb);
|
||||||
|
extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
|
||||||
|
struct strbuf *,
|
||||||
|
int abbrev, const char *subject,
|
||||||
|
const char *after_subject, enum date_mode);
|
||||||
|
|
||||||
/** Removes the first commit from a list sorted by date, and adds all
|
/** Removes the first commit from a list sorted by date, and adds all
|
||||||
* of its parents.
|
* of its parents.
|
||||||
|
@ -104,7 +104,7 @@ AC_MSG_NOTICE([CHECKS for programs])
|
|||||||
#
|
#
|
||||||
AC_PROG_CC([cc gcc])
|
AC_PROG_CC([cc gcc])
|
||||||
#AC_PROG_INSTALL # needs install-sh or install.sh in sources
|
#AC_PROG_INSTALL # needs install-sh or install.sh in sources
|
||||||
AC_CHECK_TOOL(AR, ar, :)
|
AC_CHECK_TOOLS(AR, [gar ar], :)
|
||||||
AC_CHECK_PROGS(TAR, [gtar tar])
|
AC_CHECK_PROGS(TAR, [gtar tar])
|
||||||
# TCLTK_PATH will be set to some value if we want Tcl/Tk
|
# TCLTK_PATH will be set to some value if we want Tcl/Tk
|
||||||
# or will be empty otherwise.
|
# or will be empty otherwise.
|
||||||
|
25
connect.c
25
connect.c
@ -393,9 +393,7 @@ static int git_proxy_command_options(const char *var, const char *value)
|
|||||||
if (matchlen == 4 &&
|
if (matchlen == 4 &&
|
||||||
!memcmp(value, "none", 4))
|
!memcmp(value, "none", 4))
|
||||||
matchlen = 0;
|
matchlen = 0;
|
||||||
git_proxy_command = xmalloc(matchlen + 1);
|
git_proxy_command = xmemdupz(value, matchlen);
|
||||||
memcpy(git_proxy_command, value, matchlen);
|
|
||||||
git_proxy_command[matchlen] = 0;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -579,16 +577,13 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
|
|||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
die("unable to fork");
|
die("unable to fork");
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
char command[MAX_CMD_LEN];
|
struct strbuf cmd;
|
||||||
char *posn = command;
|
|
||||||
int size = MAX_CMD_LEN;
|
|
||||||
int of = 0;
|
|
||||||
|
|
||||||
of |= add_to_string(&posn, &size, prog, 0);
|
strbuf_init(&cmd, MAX_CMD_LEN);
|
||||||
of |= add_to_string(&posn, &size, " ", 0);
|
strbuf_addstr(&cmd, prog);
|
||||||
of |= add_to_string(&posn, &size, path, 1);
|
strbuf_addch(&cmd, ' ');
|
||||||
|
sq_quote_buf(&cmd, path);
|
||||||
if (of)
|
if (cmd.len >= MAX_CMD_LEN)
|
||||||
die("command line too long");
|
die("command line too long");
|
||||||
|
|
||||||
dup2(pipefd[1][0], 0);
|
dup2(pipefd[1][0], 0);
|
||||||
@ -608,10 +603,10 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
|
|||||||
ssh_basename++;
|
ssh_basename++;
|
||||||
|
|
||||||
if (!port)
|
if (!port)
|
||||||
execlp(ssh, ssh_basename, host, command, NULL);
|
execlp(ssh, ssh_basename, host, cmd.buf, NULL);
|
||||||
else
|
else
|
||||||
execlp(ssh, ssh_basename, "-p", port, host,
|
execlp(ssh, ssh_basename, "-p", port, host,
|
||||||
command, NULL);
|
cmd.buf, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unsetenv(ALTERNATE_DB_ENVIRONMENT);
|
unsetenv(ALTERNATE_DB_ENVIRONMENT);
|
||||||
@ -620,7 +615,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
|
|||||||
unsetenv(GIT_WORK_TREE_ENVIRONMENT);
|
unsetenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||||
unsetenv(GRAFT_ENVIRONMENT);
|
unsetenv(GRAFT_ENVIRONMENT);
|
||||||
unsetenv(INDEX_ENVIRONMENT);
|
unsetenv(INDEX_ENVIRONMENT);
|
||||||
execlp("sh", "sh", "-c", command, NULL);
|
execlp("sh", "sh", "-c", cmd.buf, NULL);
|
||||||
}
|
}
|
||||||
die("exec failed");
|
die("exec failed");
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,6 @@ __git_commands ()
|
|||||||
check-attr) : plumbing;;
|
check-attr) : plumbing;;
|
||||||
check-ref-format) : plumbing;;
|
check-ref-format) : plumbing;;
|
||||||
commit-tree) : plumbing;;
|
commit-tree) : plumbing;;
|
||||||
convert-objects) : plumbing;;
|
|
||||||
cvsexportcommit) : export;;
|
cvsexportcommit) : export;;
|
||||||
cvsimport) : import;;
|
cvsimport) : import;;
|
||||||
cvsserver) : daemon;;
|
cvsserver) : daemon;;
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
;; TODO
|
;; TODO
|
||||||
;; - portability to XEmacs
|
;; - portability to XEmacs
|
||||||
;; - better handling of subprocess errors
|
;; - better handling of subprocess errors
|
||||||
;; - hook into file save (after-save-hook)
|
|
||||||
;; - diff against other branch
|
;; - diff against other branch
|
||||||
;; - renaming files from the status buffer
|
;; - renaming files from the status buffer
|
||||||
;; - creating tags
|
;; - creating tags
|
||||||
@ -220,22 +219,15 @@ and returns the process output as a string."
|
|||||||
(message "Running git %s...done" (car args))
|
(message "Running git %s...done" (car args))
|
||||||
buffer))
|
buffer))
|
||||||
|
|
||||||
(defun git-run-command (buffer env &rest args)
|
|
||||||
(message "Running git %s..." (car args))
|
|
||||||
(apply #'git-call-process-env buffer env args)
|
|
||||||
(message "Running git %s...done" (car args)))
|
|
||||||
|
|
||||||
(defun git-run-command-region (buffer start end env &rest args)
|
(defun git-run-command-region (buffer start end env &rest args)
|
||||||
"Run a git command with specified buffer region as input."
|
"Run a git command with specified buffer region as input."
|
||||||
(message "Running git %s..." (car args))
|
|
||||||
(unless (eq 0 (if env
|
(unless (eq 0 (if env
|
||||||
(git-run-process-region
|
(git-run-process-region
|
||||||
buffer start end "env"
|
buffer start end "env"
|
||||||
(append (git-get-env-strings env) (list "git") args))
|
(append (git-get-env-strings env) (list "git") args))
|
||||||
(git-run-process-region
|
(git-run-process-region
|
||||||
buffer start end "git" args)))
|
buffer start end "git" args)))
|
||||||
(error "Failed to run \"git %s\":\n%s" (mapconcat (lambda (x) x) args " ") (buffer-string)))
|
(error "Failed to run \"git %s\":\n%s" (mapconcat (lambda (x) x) args " ") (buffer-string))))
|
||||||
(message "Running git %s...done" (car args)))
|
|
||||||
|
|
||||||
(defun git-run-hook (hook env &rest args)
|
(defun git-run-hook (hook env &rest args)
|
||||||
"Run a git hook and display its output if any."
|
"Run a git hook and display its output if any."
|
||||||
@ -312,6 +304,13 @@ and returns the process output as a string."
|
|||||||
"\"")
|
"\"")
|
||||||
name))
|
name))
|
||||||
|
|
||||||
|
(defun git-success-message (text files)
|
||||||
|
"Print a success message after having handled FILES."
|
||||||
|
(let ((n (length files)))
|
||||||
|
(if (equal n 1)
|
||||||
|
(message "%s %s" text (car files))
|
||||||
|
(message "%s %d files" text n))))
|
||||||
|
|
||||||
(defun git-get-top-dir (dir)
|
(defun git-get-top-dir (dir)
|
||||||
"Retrieve the top-level directory of a git tree."
|
"Retrieve the top-level directory of a git tree."
|
||||||
(let ((cdup (with-output-to-string
|
(let ((cdup (with-output-to-string
|
||||||
@ -338,7 +337,7 @@ and returns the process output as a string."
|
|||||||
(sort-lines nil (point-min) (point-max))
|
(sort-lines nil (point-min) (point-max))
|
||||||
(save-buffer))
|
(save-buffer))
|
||||||
(when created
|
(when created
|
||||||
(git-run-command nil nil "update-index" "--add" "--" (file-relative-name ignore-name)))
|
(git-call-process-env nil nil "update-index" "--add" "--" (file-relative-name ignore-name)))
|
||||||
(git-update-status-files (list (file-relative-name ignore-name)) 'unknown)))
|
(git-update-status-files (list (file-relative-name ignore-name)) 'unknown)))
|
||||||
|
|
||||||
; propertize definition for XEmacs, stolen from erc-compat
|
; propertize definition for XEmacs, stolen from erc-compat
|
||||||
@ -485,33 +484,34 @@ and returns the process output as a string."
|
|||||||
"Remove everything from the status list."
|
"Remove everything from the status list."
|
||||||
(ewoc-filter status (lambda (info) nil)))
|
(ewoc-filter status (lambda (info) nil)))
|
||||||
|
|
||||||
(defun git-set-files-state (files state)
|
(defun git-set-fileinfo-state (info state)
|
||||||
"Set the state of a list of files."
|
"Set the state of a file info."
|
||||||
(dolist (info files)
|
|
||||||
(unless (eq (git-fileinfo->state info) state)
|
(unless (eq (git-fileinfo->state info) state)
|
||||||
(setf (git-fileinfo->state info) state)
|
(setf (git-fileinfo->state info) state
|
||||||
(setf (git-fileinfo->rename-state info) nil)
|
(git-fileinfo->old-perm info) 0
|
||||||
(setf (git-fileinfo->orig-name info) nil)
|
(git-fileinfo->new-perm info) 0
|
||||||
(setf (git-fileinfo->needs-refresh info) t))))
|
(git-fileinfo->rename-state info) nil
|
||||||
|
(git-fileinfo->orig-name info) nil
|
||||||
|
(git-fileinfo->needs-refresh info) t)))
|
||||||
|
|
||||||
(defun git-set-filenames-state (status files state)
|
(defun git-status-filenames-map (status func files &rest args)
|
||||||
"Set the state of a list of named files."
|
"Apply FUNC to the status files names in the FILES list."
|
||||||
(when files
|
(when files
|
||||||
(setq files (sort files #'string-lessp))
|
(setq files (sort files #'string-lessp))
|
||||||
(let ((file (pop files))
|
(let ((file (pop files))
|
||||||
(node (ewoc-nth status 0)))
|
(node (ewoc-nth status 0)))
|
||||||
(while (and file node)
|
(while (and file node)
|
||||||
(let ((info (ewoc-data node)))
|
(let ((info (ewoc-data node)))
|
||||||
(cond ((string-lessp (git-fileinfo->name info) file)
|
(if (string-lessp (git-fileinfo->name info) file)
|
||||||
(setq node (ewoc-next status node)))
|
(setq node (ewoc-next status node))
|
||||||
((string-equal (git-fileinfo->name info) file)
|
(if (string-equal (git-fileinfo->name info) file)
|
||||||
(unless (eq (git-fileinfo->state info) state)
|
(apply func info args))
|
||||||
(setf (git-fileinfo->state info) state)
|
(setq file (pop files))))))))
|
||||||
(setf (git-fileinfo->rename-state info) nil)
|
|
||||||
(setf (git-fileinfo->orig-name info) nil)
|
(defun git-set-filenames-state (status files state)
|
||||||
(setf (git-fileinfo->needs-refresh info) t))
|
"Set the state of a list of named files."
|
||||||
(setq file (pop files)))
|
(when files
|
||||||
(t (setq file (pop files)))))))
|
(git-status-filenames-map status #'git-set-fileinfo-state files state)
|
||||||
(unless state ;; delete files whose state has been set to nil
|
(unless state ;; delete files whose state has been set to nil
|
||||||
(ewoc-filter status (lambda (info) (git-fileinfo->state info))))))
|
(ewoc-filter status (lambda (info) (git-fileinfo->state info))))))
|
||||||
|
|
||||||
@ -599,7 +599,7 @@ and returns the process output as a string."
|
|||||||
Return the list of files that haven't been handled."
|
Return the list of files that haven't been handled."
|
||||||
(let (infolist)
|
(let (infolist)
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(apply #'git-run-command t nil "diff-index" "-z" "-M" "HEAD" "--" files)
|
(apply #'git-call-process-env t nil "diff-index" "-z" "-M" "HEAD" "--" files)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (re-search-forward
|
(while (re-search-forward
|
||||||
":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMU]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0"
|
":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMU]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0"
|
||||||
@ -632,7 +632,7 @@ Return the list of files that haven't been handled."
|
|||||||
Return the list of files that haven't been handled."
|
Return the list of files that haven't been handled."
|
||||||
(let (infolist)
|
(let (infolist)
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(apply #'git-run-command t nil "ls-files" "-z" (append options (list "--") files))
|
(apply #'git-call-process-env t nil "ls-files" "-z" (append options (list "--") files))
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
|
(while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
|
||||||
(let ((name (match-string 1)))
|
(let ((name (match-string 1)))
|
||||||
@ -644,7 +644,7 @@ Return the list of files that haven't been handled."
|
|||||||
(defun git-run-ls-unmerged (status files)
|
(defun git-run-ls-unmerged (status files)
|
||||||
"Run git-ls-files -u on FILES and parse the results into STATUS."
|
"Run git-ls-files -u on FILES and parse the results into STATUS."
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(apply #'git-run-command t nil "ls-files" "-z" "-u" "--" files)
|
(apply #'git-call-process-env t nil "ls-files" "-z" "-u" "--" files)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(let (unmerged-files)
|
(let (unmerged-files)
|
||||||
(while (re-search-forward "[0-7]\\{6\\} [0-9a-f]\\{40\\} [123]\t\\([^\0]+\\)\0" nil t)
|
(while (re-search-forward "[0-7]\\{6\\} [0-9a-f]\\{40\\} [123]\t\\([^\0]+\\)\0" nil t)
|
||||||
@ -747,11 +747,11 @@ Return the list of files that haven't been handled."
|
|||||||
('deleted (push info deleted))
|
('deleted (push info deleted))
|
||||||
('modified (push info modified))))
|
('modified (push info modified))))
|
||||||
(when added
|
(when added
|
||||||
(apply #'git-run-command nil env "update-index" "--add" "--" (git-get-filenames added)))
|
(apply #'git-call-process-env nil env "update-index" "--add" "--" (git-get-filenames added)))
|
||||||
(when deleted
|
(when deleted
|
||||||
(apply #'git-run-command nil env "update-index" "--remove" "--" (git-get-filenames deleted)))
|
(apply #'git-call-process-env nil env "update-index" "--remove" "--" (git-get-filenames deleted)))
|
||||||
(when modified
|
(when modified
|
||||||
(apply #'git-run-command nil env "update-index" "--" (git-get-filenames modified)))))
|
(apply #'git-call-process-env nil env "update-index" "--" (git-get-filenames modified)))))
|
||||||
|
|
||||||
(defun git-run-pre-commit-hook ()
|
(defun git-run-pre-commit-hook ()
|
||||||
"Run the pre-commit hook if any."
|
"Run the pre-commit hook if any."
|
||||||
@ -783,6 +783,7 @@ Return the list of files that haven't been handled."
|
|||||||
head-tree (git-rev-parse "HEAD^{tree}")))
|
head-tree (git-rev-parse "HEAD^{tree}")))
|
||||||
(if files
|
(if files
|
||||||
(progn
|
(progn
|
||||||
|
(message "Running git commit...")
|
||||||
(git-read-tree head-tree index-file)
|
(git-read-tree head-tree index-file)
|
||||||
(git-update-index nil files) ;update both the default index
|
(git-update-index nil files) ;update both the default index
|
||||||
(git-update-index index-file files) ;and the temporary one
|
(git-update-index index-file files) ;and the temporary one
|
||||||
@ -793,8 +794,8 @@ Return the list of files that haven't been handled."
|
|||||||
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
|
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
|
||||||
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
|
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
|
||||||
(with-current-buffer buffer (erase-buffer))
|
(with-current-buffer buffer (erase-buffer))
|
||||||
(git-set-files-state files 'uptodate)
|
(dolist (info files) (git-set-fileinfo-state info 'uptodate))
|
||||||
(git-run-command nil nil "rerere")
|
(git-call-process-env nil nil "rerere")
|
||||||
(git-refresh-files)
|
(git-refresh-files)
|
||||||
(git-refresh-ewoc-hf git-status)
|
(git-refresh-ewoc-hf git-status)
|
||||||
(message "Committed %s." commit)
|
(message "Committed %s." commit)
|
||||||
@ -905,8 +906,9 @@ Return the list of files that haven't been handled."
|
|||||||
(let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
|
(let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
|
||||||
(unless files
|
(unless files
|
||||||
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
|
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
|
||||||
(apply #'git-run-command nil nil "update-index" "--add" "--" files)
|
(apply #'git-call-process-env nil nil "update-index" "--add" "--" files)
|
||||||
(git-update-status-files files 'uptodate)))
|
(git-update-status-files files 'uptodate)
|
||||||
|
(git-success-message "Added" files)))
|
||||||
|
|
||||||
(defun git-ignore-file ()
|
(defun git-ignore-file ()
|
||||||
"Add marked file(s) to the ignore list."
|
"Add marked file(s) to the ignore list."
|
||||||
@ -915,7 +917,8 @@ Return the list of files that haven't been handled."
|
|||||||
(unless files
|
(unless files
|
||||||
(push (file-relative-name (read-file-name "File to ignore: " nil nil t)) files))
|
(push (file-relative-name (read-file-name "File to ignore: " nil nil t)) files))
|
||||||
(dolist (f files) (git-append-to-ignore f))
|
(dolist (f files) (git-append-to-ignore f))
|
||||||
(git-update-status-files files 'ignored)))
|
(git-update-status-files files 'ignored)
|
||||||
|
(git-success-message "Ignored" files)))
|
||||||
|
|
||||||
(defun git-remove-file ()
|
(defun git-remove-file ()
|
||||||
"Remove the marked file(s)."
|
"Remove the marked file(s)."
|
||||||
@ -928,8 +931,9 @@ Return the list of files that haven't been handled."
|
|||||||
(progn
|
(progn
|
||||||
(dolist (name files)
|
(dolist (name files)
|
||||||
(when (file-exists-p name) (delete-file name)))
|
(when (file-exists-p name) (delete-file name)))
|
||||||
(apply #'git-run-command nil nil "update-index" "--remove" "--" files)
|
(apply #'git-call-process-env nil nil "update-index" "--remove" "--" files)
|
||||||
(git-update-status-files files nil))
|
(git-update-status-files files nil)
|
||||||
|
(git-success-message "Removed" files))
|
||||||
(message "Aborting"))))
|
(message "Aborting"))))
|
||||||
|
|
||||||
(defun git-revert-file ()
|
(defun git-revert-file ()
|
||||||
@ -947,18 +951,20 @@ Return the list of files that haven't been handled."
|
|||||||
('unmerged (push (git-fileinfo->name info) modified))
|
('unmerged (push (git-fileinfo->name info) modified))
|
||||||
('modified (push (git-fileinfo->name info) modified))))
|
('modified (push (git-fileinfo->name info) modified))))
|
||||||
(when added
|
(when added
|
||||||
(apply #'git-run-command nil nil "update-index" "--force-remove" "--" added))
|
(apply #'git-call-process-env nil nil "update-index" "--force-remove" "--" added))
|
||||||
(when modified
|
(when modified
|
||||||
(apply #'git-run-command nil nil "checkout" "HEAD" modified))
|
(apply #'git-call-process-env nil nil "checkout" "HEAD" modified))
|
||||||
(git-update-status-files (append added modified) 'uptodate))))
|
(git-update-status-files (append added modified) 'uptodate)
|
||||||
|
(git-success-message "Reverted" files))))
|
||||||
|
|
||||||
(defun git-resolve-file ()
|
(defun git-resolve-file ()
|
||||||
"Resolve conflicts in marked file(s)."
|
"Resolve conflicts in marked file(s)."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
|
(let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
|
||||||
(when files
|
(when files
|
||||||
(apply #'git-run-command nil nil "update-index" "--" files)
|
(apply #'git-call-process-env nil nil "update-index" "--" files)
|
||||||
(git-update-status-files files 'uptodate))))
|
(git-update-status-files files 'uptodate)
|
||||||
|
(git-success-message "Resolved" files))))
|
||||||
|
|
||||||
(defun git-remove-handled ()
|
(defun git-remove-handled ()
|
||||||
"Remove handled files from the status list."
|
"Remove handled files from the status list."
|
||||||
@ -985,9 +991,11 @@ Return the list of files that haven't been handled."
|
|||||||
(interactive)
|
(interactive)
|
||||||
(if (setq git-show-ignored (not git-show-ignored))
|
(if (setq git-show-ignored (not git-show-ignored))
|
||||||
(progn
|
(progn
|
||||||
|
(message "Inserting ignored files...")
|
||||||
(git-run-ls-files-with-excludes git-status nil 'ignored "-o" "-i")
|
(git-run-ls-files-with-excludes git-status nil 'ignored "-o" "-i")
|
||||||
(git-refresh-files)
|
(git-refresh-files)
|
||||||
(git-refresh-ewoc-hf git-status))
|
(git-refresh-ewoc-hf git-status)
|
||||||
|
(message "Inserting ignored files...done"))
|
||||||
(git-remove-handled)))
|
(git-remove-handled)))
|
||||||
|
|
||||||
(defun git-toggle-show-unknown ()
|
(defun git-toggle-show-unknown ()
|
||||||
@ -995,9 +1003,11 @@ Return the list of files that haven't been handled."
|
|||||||
(interactive)
|
(interactive)
|
||||||
(if (setq git-show-unknown (not git-show-unknown))
|
(if (setq git-show-unknown (not git-show-unknown))
|
||||||
(progn
|
(progn
|
||||||
|
(message "Inserting unknown files...")
|
||||||
(git-run-ls-files-with-excludes git-status nil 'unknown "-o")
|
(git-run-ls-files-with-excludes git-status nil 'unknown "-o")
|
||||||
(git-refresh-files)
|
(git-refresh-files)
|
||||||
(git-refresh-ewoc-hf git-status))
|
(git-refresh-ewoc-hf git-status)
|
||||||
|
(message "Inserting unknown files...done"))
|
||||||
(git-remove-handled)))
|
(git-remove-handled)))
|
||||||
|
|
||||||
(defun git-setup-diff-buffer (buffer)
|
(defun git-setup-diff-buffer (buffer)
|
||||||
@ -1197,12 +1207,23 @@ Return the list of files that haven't been handled."
|
|||||||
(interactive)
|
(interactive)
|
||||||
(let* ((status git-status)
|
(let* ((status git-status)
|
||||||
(pos (ewoc-locate status))
|
(pos (ewoc-locate status))
|
||||||
|
(marked-files (git-get-filenames (ewoc-collect status (lambda (info) (git-fileinfo->marked info)))))
|
||||||
(cur-name (and pos (git-fileinfo->name (ewoc-data pos)))))
|
(cur-name (and pos (git-fileinfo->name (ewoc-data pos)))))
|
||||||
(unless status (error "Not in git-status buffer."))
|
(unless status (error "Not in git-status buffer."))
|
||||||
(git-run-command nil nil "update-index" "--refresh")
|
(message "Refreshing git status...")
|
||||||
|
(git-call-process-env nil nil "update-index" "--refresh")
|
||||||
(git-clear-status status)
|
(git-clear-status status)
|
||||||
(git-update-status-files nil)
|
(git-update-status-files nil)
|
||||||
|
; restore file marks
|
||||||
|
(when marked-files
|
||||||
|
(git-status-filenames-map status
|
||||||
|
(lambda (info)
|
||||||
|
(setf (git-fileinfo->marked info) t)
|
||||||
|
(setf (git-fileinfo->needs-refresh info) t))
|
||||||
|
marked-files)
|
||||||
|
(git-refresh-files))
|
||||||
; move point to the current file name if any
|
; move point to the current file name if any
|
||||||
|
(message "Refreshing git status...done")
|
||||||
(let ((node (and cur-name (git-find-status-file status cur-name))))
|
(let ((node (and cur-name (git-find-status-file status cur-name))))
|
||||||
(when node (ewoc-goto-node status node)))))
|
(when node (ewoc-goto-node status node)))))
|
||||||
|
|
||||||
@ -1324,9 +1345,24 @@ Commands:
|
|||||||
(cd dir)
|
(cd dir)
|
||||||
(git-status-mode)
|
(git-status-mode)
|
||||||
(git-refresh-status)
|
(git-refresh-status)
|
||||||
(goto-char (point-min)))
|
(goto-char (point-min))
|
||||||
|
(add-hook 'after-save-hook 'git-update-saved-file))
|
||||||
(message "%s is not a git working tree." dir)))
|
(message "%s is not a git working tree." dir)))
|
||||||
|
|
||||||
|
(defun git-update-saved-file ()
|
||||||
|
"Update the corresponding git-status buffer when a file is saved.
|
||||||
|
Meant to be used in `after-save-hook'."
|
||||||
|
(let* ((file (expand-file-name buffer-file-name))
|
||||||
|
(dir (condition-case nil (git-get-top-dir (file-name-directory file))))
|
||||||
|
(buffer (and dir (git-find-status-buffer dir))))
|
||||||
|
(when buffer
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(let ((filename (file-relative-name file dir)))
|
||||||
|
; skip files located inside the .git directory
|
||||||
|
(unless (string-match "^\\.git/" filename)
|
||||||
|
(git-call-process-env nil nil "add" "--refresh" "--" filename)
|
||||||
|
(git-update-status-files (list filename) 'uptodate)))))))
|
||||||
|
|
||||||
(defun git-help ()
|
(defun git-help ()
|
||||||
"Display help for Git mode."
|
"Display help for Git mode."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -27,7 +27,7 @@ shallow_depth=
|
|||||||
no_progress=
|
no_progress=
|
||||||
test -t 1 || no_progress=--no-progress
|
test -t 1 || no_progress=--no-progress
|
||||||
quiet=
|
quiet=
|
||||||
while case "$#" in 0) break ;; esac
|
while test $# != 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-a|--a|--ap|--app|--appe|--appen|--append)
|
-a|--a|--ap|--app|--appe|--appen|--append)
|
||||||
|
@ -9,7 +9,7 @@ SUBDIRECTORY_OK=Yes
|
|||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
no_prune=:
|
no_prune=:
|
||||||
while case $# in 0) break ;; esac
|
while test $# != 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--prune)
|
--prune)
|
||||||
|
@ -11,7 +11,7 @@ require_work_tree
|
|||||||
update= reset_type=--mixed
|
update= reset_type=--mixed
|
||||||
unset rev
|
unset rev
|
||||||
|
|
||||||
while case $# in 0) break ;; esac
|
while test $# != 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--mixed | --soft | --hard)
|
--mixed | --soft | --hard)
|
||||||
|
@ -14,7 +14,7 @@ username=
|
|||||||
list=
|
list=
|
||||||
verify=
|
verify=
|
||||||
LINES=0
|
LINES=0
|
||||||
while case "$#" in 0) break ;; esac
|
while test $# != 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-a)
|
-a)
|
||||||
|
@ -5,7 +5,7 @@ SUBDIRECTORY_OK='Yes'
|
|||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
verbose=
|
verbose=
|
||||||
while case $# in 0) break;; esac
|
while test $# != 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
|
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
|
||||||
|
@ -63,6 +63,14 @@ def system(cmd):
|
|||||||
if os.system(cmd) != 0:
|
if os.system(cmd) != 0:
|
||||||
die("command failed: %s" % cmd)
|
die("command failed: %s" % cmd)
|
||||||
|
|
||||||
|
def isP4Exec(kind):
|
||||||
|
"""Determine if a Perforce 'kind' should have execute permission
|
||||||
|
|
||||||
|
'p4 help filetypes' gives a list of the types. If it starts with 'x',
|
||||||
|
or x follows one of a few letters. Otherwise, if there is an 'x' after
|
||||||
|
a plus sign, it is also executable"""
|
||||||
|
return (re.search(r"(^[cku]?x)|\+.*x", kind) != None)
|
||||||
|
|
||||||
def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
|
def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
|
||||||
cmd = "p4 -G %s" % cmd
|
cmd = "p4 -G %s" % cmd
|
||||||
if verbose:
|
if verbose:
|
||||||
@ -932,7 +940,7 @@ class P4Sync(Command):
|
|||||||
data = file['data']
|
data = file['data']
|
||||||
|
|
||||||
mode = "644"
|
mode = "644"
|
||||||
if file["type"].startswith("x"):
|
if isP4Exec(file["type"]):
|
||||||
mode = "755"
|
mode = "755"
|
||||||
elif file["type"] == "symlink":
|
elif file["type"] == "symlink":
|
||||||
mode = "120000"
|
mode = "120000"
|
||||||
@ -1643,6 +1651,7 @@ def printUsage(commands):
|
|||||||
commands = {
|
commands = {
|
||||||
"debug" : P4Debug,
|
"debug" : P4Debug,
|
||||||
"submit" : P4Submit,
|
"submit" : P4Submit,
|
||||||
|
"commit" : P4Submit,
|
||||||
"sync" : P4Sync,
|
"sync" : P4Sync,
|
||||||
"rebase" : P4Rebase,
|
"rebase" : P4Rebase,
|
||||||
"clone" : P4Clone,
|
"clone" : P4Clone,
|
||||||
|
@ -27,12 +27,20 @@ import math
|
|||||||
import string
|
import string
|
||||||
import fcntl
|
import fcntl
|
||||||
|
|
||||||
|
try:
|
||||||
|
import gtksourceview2
|
||||||
|
have_gtksourceview2 = True
|
||||||
|
except ImportError:
|
||||||
|
have_gtksourceview2 = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import gtksourceview
|
import gtksourceview
|
||||||
have_gtksourceview = True
|
have_gtksourceview = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
have_gtksourceview = False
|
have_gtksourceview = False
|
||||||
print "Running without gtksourceview module"
|
|
||||||
|
if not have_gtksourceview2 and not have_gtksourceview:
|
||||||
|
print "Running without gtksourceview2 or gtksourceview module"
|
||||||
|
|
||||||
re_ident = re.compile('(author|committer) (?P<ident>.*) (?P<epoch>\d+) (?P<tz>[+-]\d{4})')
|
re_ident = re.compile('(author|committer) (?P<ident>.*) (?P<epoch>\d+) (?P<tz>[+-]\d{4})')
|
||||||
|
|
||||||
@ -58,6 +66,26 @@ def show_date(epoch, tz):
|
|||||||
|
|
||||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(secs))
|
return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(secs))
|
||||||
|
|
||||||
|
def get_source_buffer_and_view():
|
||||||
|
if have_gtksourceview2:
|
||||||
|
buffer = gtksourceview2.Buffer()
|
||||||
|
slm = gtksourceview2.LanguageManager()
|
||||||
|
gsl = slm.get_language("diff")
|
||||||
|
buffer.set_highlight_syntax(True)
|
||||||
|
buffer.set_language(gsl)
|
||||||
|
view = gtksourceview2.View(buffer)
|
||||||
|
elif have_gtksourceview:
|
||||||
|
buffer = gtksourceview.SourceBuffer()
|
||||||
|
slm = gtksourceview.SourceLanguagesManager()
|
||||||
|
gsl = slm.get_language_from_mime_type("text/x-patch")
|
||||||
|
buffer.set_highlight(True)
|
||||||
|
buffer.set_language(gsl)
|
||||||
|
view = gtksourceview.SourceView(buffer)
|
||||||
|
else:
|
||||||
|
buffer = gtk.TextBuffer()
|
||||||
|
view = gtk.TextView(buffer)
|
||||||
|
return (buffer, view)
|
||||||
|
|
||||||
|
|
||||||
class CellRendererGraph(gtk.GenericCellRenderer):
|
class CellRendererGraph(gtk.GenericCellRenderer):
|
||||||
"""Cell renderer for directed graph.
|
"""Cell renderer for directed graph.
|
||||||
@ -582,17 +610,7 @@ class DiffWindow(object):
|
|||||||
hpan.pack1(scrollwin, True, True)
|
hpan.pack1(scrollwin, True, True)
|
||||||
scrollwin.show()
|
scrollwin.show()
|
||||||
|
|
||||||
if have_gtksourceview:
|
(self.buffer, sourceview) = get_source_buffer_and_view()
|
||||||
self.buffer = gtksourceview.SourceBuffer()
|
|
||||||
slm = gtksourceview.SourceLanguagesManager()
|
|
||||||
gsl = slm.get_language_from_mime_type("text/x-patch")
|
|
||||||
self.buffer.set_highlight(True)
|
|
||||||
self.buffer.set_language(gsl)
|
|
||||||
sourceview = gtksourceview.SourceView(self.buffer)
|
|
||||||
else:
|
|
||||||
self.buffer = gtk.TextBuffer()
|
|
||||||
sourceview = gtk.TextView(self.buffer)
|
|
||||||
|
|
||||||
|
|
||||||
sourceview.set_editable(False)
|
sourceview.set_editable(False)
|
||||||
sourceview.modify_font(pango.FontDescription("Monospace"))
|
sourceview.modify_font(pango.FontDescription("Monospace"))
|
||||||
@ -956,16 +974,7 @@ class GitView(object):
|
|||||||
vbox.pack_start(scrollwin, expand=True, fill=True)
|
vbox.pack_start(scrollwin, expand=True, fill=True)
|
||||||
scrollwin.show()
|
scrollwin.show()
|
||||||
|
|
||||||
if have_gtksourceview:
|
(self.message_buffer, sourceview) = get_source_buffer_and_view()
|
||||||
self.message_buffer = gtksourceview.SourceBuffer()
|
|
||||||
slm = gtksourceview.SourceLanguagesManager()
|
|
||||||
gsl = slm.get_language_from_mime_type("text/x-patch")
|
|
||||||
self.message_buffer.set_highlight(True)
|
|
||||||
self.message_buffer.set_language(gsl)
|
|
||||||
sourceview = gtksourceview.SourceView(self.message_buffer)
|
|
||||||
else:
|
|
||||||
self.message_buffer = gtk.TextBuffer()
|
|
||||||
sourceview = gtk.TextView(self.message_buffer)
|
|
||||||
|
|
||||||
sourceview.set_editable(False)
|
sourceview.set_editable(False)
|
||||||
sourceview.modify_font(pango.FontDescription("Monospace"))
|
sourceview.modify_font(pango.FontDescription("Monospace"))
|
||||||
|
@ -29,6 +29,8 @@ hgvers = {}
|
|||||||
hgchildren = {}
|
hgchildren = {}
|
||||||
# Current branch for each hg revision
|
# Current branch for each hg revision
|
||||||
hgbranch = {}
|
hgbranch = {}
|
||||||
|
# Number of new changesets converted from hg
|
||||||
|
hgnewcsets = 0
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -40,6 +42,8 @@ def usage():
|
|||||||
options:
|
options:
|
||||||
-s, --gitstate=FILE: name of the state to be saved/read
|
-s, --gitstate=FILE: name of the state to be saved/read
|
||||||
for incrementals
|
for incrementals
|
||||||
|
-n, --nrepack=INT: number of changesets that will trigger
|
||||||
|
a repack (default=0, -1 to deactivate)
|
||||||
|
|
||||||
required:
|
required:
|
||||||
hgprj: name of the HG project to import (directory)
|
hgprj: name of the HG project to import (directory)
|
||||||
@ -68,14 +72,16 @@ def getgitenv(user, date):
|
|||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
state = ''
|
state = ''
|
||||||
|
opt_nrepack = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 's:t:', ['gitstate=', 'tempdir='])
|
opts, args = getopt.getopt(sys.argv[1:], 's:t:n:', ['gitstate=', 'tempdir=', 'nrepack='])
|
||||||
for o, a in opts:
|
for o, a in opts:
|
||||||
if o in ('-s', '--gitstate'):
|
if o in ('-s', '--gitstate'):
|
||||||
state = a
|
state = a
|
||||||
state = os.path.abspath(state)
|
state = os.path.abspath(state)
|
||||||
|
if o in ('-n', '--nrepack'):
|
||||||
|
opt_nrepack = int(a)
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
raise('params')
|
raise('params')
|
||||||
except:
|
except:
|
||||||
@ -138,6 +144,7 @@ for cset in range(int(tip) + 1):
|
|||||||
# incremental, already seen
|
# incremental, already seen
|
||||||
if hgvers.has_key(str(cset)):
|
if hgvers.has_key(str(cset)):
|
||||||
continue
|
continue
|
||||||
|
hgnewcsets += 1
|
||||||
|
|
||||||
# get info
|
# get info
|
||||||
prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
|
prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
|
||||||
@ -222,7 +229,8 @@ for cset in range(int(tip) + 1):
|
|||||||
print 'record', cset, '->', vvv
|
print 'record', cset, '->', vvv
|
||||||
hgvers[str(cset)] = vvv
|
hgvers[str(cset)] = vvv
|
||||||
|
|
||||||
os.system('git-repack -a -d')
|
if hgnewcsets >= opt_nrepack and opt_nrepack != -1:
|
||||||
|
os.system('git-repack -a -d')
|
||||||
|
|
||||||
# write the state for incrementals
|
# write the state for incrementals
|
||||||
if state:
|
if state:
|
||||||
|
@ -138,7 +138,15 @@ generate_email()
|
|||||||
|
|
||||||
# Check if we've got anyone to send to
|
# Check if we've got anyone to send to
|
||||||
if [ -z "$recipients" ]; then
|
if [ -z "$recipients" ]; then
|
||||||
echo >&2 "*** hooks.recipients is not set so no email will be sent"
|
case "$refname_type" in
|
||||||
|
"annotated tag")
|
||||||
|
config_name="hooks.announcelist"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
config_name="hooks.mailinglist"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo >&2 "*** $config_name is not set so no email will be sent"
|
||||||
echo >&2 "*** for $refname update $oldrev->$newrev"
|
echo >&2 "*** for $refname update $oldrev->$newrev"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@ -177,7 +185,6 @@ generate_email_header()
|
|||||||
# --- Email (all stdout will be the email)
|
# --- Email (all stdout will be the email)
|
||||||
# Generate header
|
# Generate header
|
||||||
cat <<-EOF
|
cat <<-EOF
|
||||||
From: $committer
|
|
||||||
To: $recipients
|
To: $recipients
|
||||||
Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
|
Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
|
||||||
X-Git-Refname: $refname
|
X-Git-Refname: $refname
|
||||||
@ -571,6 +578,15 @@ generate_delete_general_email()
|
|||||||
echo $LOGEND
|
echo $LOGEND
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send_mail()
|
||||||
|
{
|
||||||
|
if [ -n "$envelopesender" ]; then
|
||||||
|
/usr/sbin/sendmail -t -f "$envelopesender"
|
||||||
|
else
|
||||||
|
/usr/sbin/sendmail -t
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ---------------------------- main()
|
# ---------------------------- main()
|
||||||
|
|
||||||
# --- Constants
|
# --- Constants
|
||||||
@ -607,13 +623,8 @@ if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
|
|||||||
# resend an email; they could redirect the output to sendmail themselves
|
# resend an email; they could redirect the output to sendmail themselves
|
||||||
PAGER= generate_email $2 $3 $1
|
PAGER= generate_email $2 $3 $1
|
||||||
else
|
else
|
||||||
if [ -n "$envelopesender" ]; then
|
|
||||||
envelopesender="-f '$envelopesender'"
|
|
||||||
fi
|
|
||||||
|
|
||||||
while read oldrev newrev refname
|
while read oldrev newrev refname
|
||||||
do
|
do
|
||||||
generate_email $oldrev $newrev $refname |
|
generate_email $oldrev $newrev $refname | send_mail
|
||||||
/usr/sbin/sendmail -t $envelopesender
|
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
214
contrib/hooks/setgitperms.perl
Normal file
214
contrib/hooks/setgitperms.perl
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 Josh England
|
||||||
|
#
|
||||||
|
# This script can be used to save/restore full permissions and ownership data
|
||||||
|
# within a git working tree.
|
||||||
|
#
|
||||||
|
# To save permissions/ownership data, place this script in your .git/hooks
|
||||||
|
# directory and enable a `pre-commit` hook with the following lines:
|
||||||
|
# #!/bin/sh
|
||||||
|
# SUBDIRECTORY_OK=1 . git-sh-setup
|
||||||
|
# $GIT_DIR/hooks/setgitperms.perl -r
|
||||||
|
#
|
||||||
|
# To restore permissions/ownership data, place this script in your .git/hooks
|
||||||
|
# directory and enable a `post-merge` and `post-checkout` hook with the
|
||||||
|
# following lines:
|
||||||
|
# #!/bin/sh
|
||||||
|
# SUBDIRECTORY_OK=1 . git-sh-setup
|
||||||
|
# $GIT_DIR/hooks/setgitperms.perl -w
|
||||||
|
#
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use File::Find;
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
my $usage =
|
||||||
|
"Usage: setgitperms.perl [OPTION]... <--read|--write>
|
||||||
|
This program uses a file `.gitmeta` to store/restore permissions and uid/gid
|
||||||
|
info for all files/dirs tracked by git in the repository.
|
||||||
|
|
||||||
|
---------------------------------Read Mode-------------------------------------
|
||||||
|
-r, --read Reads perms/etc from working dir into a .gitmeta file
|
||||||
|
-s, --stdout Output to stdout instead of .gitmeta
|
||||||
|
-d, --diff Show unified diff of perms file (XOR with --stdout)
|
||||||
|
|
||||||
|
---------------------------------Write Mode------------------------------------
|
||||||
|
-w, --write Modify perms/etc in working dir to match the .gitmeta file
|
||||||
|
-v, --verbose Be verbose
|
||||||
|
|
||||||
|
\n";
|
||||||
|
|
||||||
|
my ($stdout, $showdiff, $verbose, $read_mode, $write_mode);
|
||||||
|
|
||||||
|
if ((@ARGV < 0) || !GetOptions(
|
||||||
|
"stdout", \$stdout,
|
||||||
|
"diff", \$showdiff,
|
||||||
|
"read", \$read_mode,
|
||||||
|
"write", \$write_mode,
|
||||||
|
"verbose", \$verbose,
|
||||||
|
)) { die $usage; }
|
||||||
|
die $usage unless ($read_mode xor $write_mode);
|
||||||
|
|
||||||
|
my $topdir = `git-rev-parse --show-cdup` or die "\n"; chomp $topdir;
|
||||||
|
my $gitdir = $topdir . '.git';
|
||||||
|
my $gitmeta = $topdir . '.gitmeta';
|
||||||
|
|
||||||
|
if ($write_mode) {
|
||||||
|
# Update the working dir permissions/ownership based on data from .gitmeta
|
||||||
|
open (IN, "<$gitmeta") or die "Could not open $gitmeta for reading: $!\n";
|
||||||
|
while (defined ($_ = <IN>)) {
|
||||||
|
chomp;
|
||||||
|
if (/^(.*) mode=(\S+)\s+uid=(\d+)\s+gid=(\d+)/) {
|
||||||
|
# Compare recorded perms to actual perms in the working dir
|
||||||
|
my ($path, $mode, $uid, $gid) = ($1, $2, $3, $4);
|
||||||
|
my $fullpath = $topdir . $path;
|
||||||
|
my (undef,undef,$wmode,undef,$wuid,$wgid) = lstat($fullpath);
|
||||||
|
$wmode = sprintf "%04o", $wmode & 07777;
|
||||||
|
if ($mode ne $wmode) {
|
||||||
|
$verbose && print "Updating permissions on $path: old=$wmode, new=$mode\n";
|
||||||
|
chmod oct($mode), $fullpath;
|
||||||
|
}
|
||||||
|
if ($uid != $wuid || $gid != $wgid) {
|
||||||
|
if ($verbose) {
|
||||||
|
# Print out user/group names instead of uid/gid
|
||||||
|
my $pwname = getpwuid($uid);
|
||||||
|
my $grpname = getgrgid($gid);
|
||||||
|
my $wpwname = getpwuid($wuid);
|
||||||
|
my $wgrpname = getgrgid($wgid);
|
||||||
|
$pwname = $uid if !defined $pwname;
|
||||||
|
$grpname = $gid if !defined $grpname;
|
||||||
|
$wpwname = $wuid if !defined $wpwname;
|
||||||
|
$wgrpname = $wgid if !defined $wgrpname;
|
||||||
|
|
||||||
|
print "Updating uid/gid on $path: old=$wpwname/$wgrpname, new=$pwname/$grpname\n";
|
||||||
|
}
|
||||||
|
chown $uid, $gid, $fullpath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn "Invalid input format in $gitmeta:\n\t$_\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close IN;
|
||||||
|
}
|
||||||
|
elsif ($read_mode) {
|
||||||
|
# Handle merge conflicts in the .gitperms file
|
||||||
|
if (-e "$gitdir/MERGE_MSG") {
|
||||||
|
if (`grep ====== $gitmeta`) {
|
||||||
|
# Conflict not resolved -- abort the commit
|
||||||
|
print "PERMISSIONS/OWNERSHIP CONFLICT\n";
|
||||||
|
print " Resolve the conflict in the $gitmeta file and then run\n";
|
||||||
|
print " `.git/hooks/setgitperms.perl --write` to reconcile.\n";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
elsif (`grep $gitmeta $gitdir/MERGE_MSG`) {
|
||||||
|
# A conflict in .gitmeta has been manually resolved. Verify that
|
||||||
|
# the working dir perms matches the current .gitmeta perms for
|
||||||
|
# each file/dir that conflicted.
|
||||||
|
# This is here because a `setgitperms.perl --write` was not
|
||||||
|
# performed due to a merge conflict, so permissions/ownership
|
||||||
|
# may not be consistent with the manually merged .gitmeta file.
|
||||||
|
my @conflict_diff = `git show \$(cat $gitdir/MERGE_HEAD)`;
|
||||||
|
my @conflict_files;
|
||||||
|
my $metadiff = 0;
|
||||||
|
|
||||||
|
# Build a list of files that conflicted from the .gitmeta diff
|
||||||
|
foreach my $line (@conflict_diff) {
|
||||||
|
if ($line =~ m|^diff --git a/$gitmeta b/$gitmeta|) {
|
||||||
|
$metadiff = 1;
|
||||||
|
}
|
||||||
|
elsif ($line =~ /^diff --git/) {
|
||||||
|
$metadiff = 0;
|
||||||
|
}
|
||||||
|
elsif ($metadiff && $line =~ /^\+(.*) mode=/) {
|
||||||
|
push @conflict_files, $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify that each conflict file now has permissions consistent
|
||||||
|
# with the .gitmeta file
|
||||||
|
foreach my $file (@conflict_files) {
|
||||||
|
my $absfile = $topdir . $file;
|
||||||
|
my $gm_entry = `grep "^$file mode=" $gitmeta`;
|
||||||
|
if ($gm_entry =~ /mode=(\d+) uid=(\d+) gid=(\d+)/) {
|
||||||
|
my ($gm_mode, $gm_uid, $gm_gid) = ($1, $2, $3);
|
||||||
|
my (undef,undef,$mode,undef,$uid,$gid) = lstat("$absfile");
|
||||||
|
$mode = sprintf("%04o", $mode & 07777);
|
||||||
|
if (($gm_mode ne $mode) || ($gm_uid != $uid)
|
||||||
|
|| ($gm_gid != $gid)) {
|
||||||
|
print "PERMISSIONS/OWNERSHIP CONFLICT\n";
|
||||||
|
print " Mismatch found for file: $file\n";
|
||||||
|
print " Run `.git/hooks/setgitperms.perl --write` to reconcile.\n";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Warning! Permissions/ownership no longer being tracked for file: $file\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# No merge conflicts -- write out perms/ownership data to .gitmeta file
|
||||||
|
unless ($stdout) {
|
||||||
|
open (OUT, ">$gitmeta.tmp") or die "Could not open $gitmeta.tmp for writing: $!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my @files = `git-ls-files`;
|
||||||
|
my %dirs;
|
||||||
|
|
||||||
|
foreach my $path (@files) {
|
||||||
|
chomp $path;
|
||||||
|
# We have to manually add stats for parent directories
|
||||||
|
my $parent = dirname($path);
|
||||||
|
while (!exists $dirs{$parent}) {
|
||||||
|
$dirs{$parent} = 1;
|
||||||
|
next if $parent eq '.';
|
||||||
|
printstats($parent);
|
||||||
|
$parent = dirname($parent);
|
||||||
|
}
|
||||||
|
# Now the git-tracked file
|
||||||
|
printstats($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
# diff the temporary metadata file to see if anything has changed
|
||||||
|
# If no metadata has changed, don't overwrite the real file
|
||||||
|
# This is just so `git commit -a` doesn't try to commit a bogus update
|
||||||
|
unless ($stdout) {
|
||||||
|
if (! -e $gitmeta) {
|
||||||
|
rename "$gitmeta.tmp", $gitmeta;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
my $diff = `diff -U 0 $gitmeta $gitmeta.tmp`;
|
||||||
|
if ($diff ne '') {
|
||||||
|
rename "$gitmeta.tmp", $gitmeta;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlink "$gitmeta.tmp";
|
||||||
|
}
|
||||||
|
if ($showdiff) {
|
||||||
|
print $diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close OUT;
|
||||||
|
}
|
||||||
|
# Make sure the .gitmeta file is tracked
|
||||||
|
system("git add $gitmeta");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub printstats {
|
||||||
|
my $path = $_[0];
|
||||||
|
$path =~ s/@/\@/g;
|
||||||
|
my (undef,undef,$mode,undef,$uid,$gid) = lstat($path);
|
||||||
|
$path =~ s/%/\%/g;
|
||||||
|
if ($stdout) {
|
||||||
|
print $path;
|
||||||
|
printf " mode=%04o uid=$uid gid=$gid\n", $mode & 07777;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print OUT $path;
|
||||||
|
printf OUT " mode=%04o uid=$uid gid=$gid\n", $mode & 07777;
|
||||||
|
}
|
||||||
|
}
|
405
convert.c
405
convert.c
@ -80,24 +80,19 @@ static int is_binary(unsigned long size, struct text_stat *stats)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep, int action)
|
static int crlf_to_git(const char *path, const char *src, size_t len,
|
||||||
|
struct strbuf *buf, int action)
|
||||||
{
|
{
|
||||||
char *buffer, *dst;
|
|
||||||
unsigned long size, nsize;
|
|
||||||
struct text_stat stats;
|
struct text_stat stats;
|
||||||
|
char *dst;
|
||||||
|
|
||||||
if ((action == CRLF_BINARY) || !auto_crlf)
|
if ((action == CRLF_BINARY) || !auto_crlf || !len)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
size = *sizep;
|
|
||||||
if (!size)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
gather_stats(src, size, &stats);
|
|
||||||
|
|
||||||
|
gather_stats(src, len, &stats);
|
||||||
/* No CR? Nothing to convert, regardless. */
|
/* No CR? Nothing to convert, regardless. */
|
||||||
if (!stats.cr)
|
if (!stats.cr)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
if (action == CRLF_GUESS) {
|
if (action == CRLF_GUESS) {
|
||||||
/*
|
/*
|
||||||
@ -106,24 +101,19 @@ static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep
|
|||||||
* stuff?
|
* stuff?
|
||||||
*/
|
*/
|
||||||
if (stats.cr != stats.crlf)
|
if (stats.cr != stats.crlf)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And add some heuristics for binary vs text, of course...
|
* And add some heuristics for binary vs text, of course...
|
||||||
*/
|
*/
|
||||||
if (is_binary(size, &stats))
|
if (is_binary(len, &stats))
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* only grow if not in place */
|
||||||
* Ok, allocate a new buffer, fill it in, and return it
|
if (strbuf_avail(buf) + buf->len < len)
|
||||||
* to let the caller know that we switched buffers.
|
strbuf_grow(buf, len - buf->len);
|
||||||
*/
|
dst = buf->buf;
|
||||||
nsize = size - stats.crlf;
|
|
||||||
buffer = xmalloc(nsize);
|
|
||||||
*sizep = nsize;
|
|
||||||
|
|
||||||
dst = buffer;
|
|
||||||
if (action == CRLF_GUESS) {
|
if (action == CRLF_GUESS) {
|
||||||
/*
|
/*
|
||||||
* If we guessed, we already know we rejected a file with
|
* If we guessed, we already know we rejected a file with
|
||||||
@ -134,71 +124,72 @@ static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep
|
|||||||
unsigned char c = *src++;
|
unsigned char c = *src++;
|
||||||
if (c != '\r')
|
if (c != '\r')
|
||||||
*dst++ = c;
|
*dst++ = c;
|
||||||
} while (--size);
|
} while (--len);
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
unsigned char c = *src++;
|
unsigned char c = *src++;
|
||||||
if (! (c == '\r' && (1 < size && *src == '\n')))
|
if (! (c == '\r' && (1 < len && *src == '\n')))
|
||||||
*dst++ = c;
|
*dst++ = c;
|
||||||
} while (--size);
|
} while (--len);
|
||||||
}
|
}
|
||||||
|
strbuf_setlen(buf, dst - buf->buf);
|
||||||
return buffer;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *crlf_to_worktree(const char *path, const char *src, unsigned long *sizep, int action)
|
static int crlf_to_worktree(const char *path, const char *src, size_t len,
|
||||||
|
struct strbuf *buf, int action)
|
||||||
{
|
{
|
||||||
char *buffer, *dst;
|
char *to_free = NULL;
|
||||||
unsigned long size, nsize;
|
|
||||||
struct text_stat stats;
|
struct text_stat stats;
|
||||||
unsigned char last;
|
|
||||||
|
|
||||||
if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
|
if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
|
||||||
auto_crlf <= 0)
|
auto_crlf <= 0)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
size = *sizep;
|
if (!len)
|
||||||
if (!size)
|
return 0;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
gather_stats(src, size, &stats);
|
gather_stats(src, len, &stats);
|
||||||
|
|
||||||
/* No LF? Nothing to convert, regardless. */
|
/* No LF? Nothing to convert, regardless. */
|
||||||
if (!stats.lf)
|
if (!stats.lf)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
/* Was it already in CRLF format? */
|
/* Was it already in CRLF format? */
|
||||||
if (stats.lf == stats.crlf)
|
if (stats.lf == stats.crlf)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
if (action == CRLF_GUESS) {
|
if (action == CRLF_GUESS) {
|
||||||
/* If we have any bare CR characters, we're not going to touch it */
|
/* If we have any bare CR characters, we're not going to touch it */
|
||||||
if (stats.cr != stats.crlf)
|
if (stats.cr != stats.crlf)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
if (is_binary(size, &stats))
|
if (is_binary(len, &stats))
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* are we "faking" in place editing ? */
|
||||||
* Ok, allocate a new buffer, fill it in, and return it
|
if (src == buf->buf)
|
||||||
* to let the caller know that we switched buffers.
|
to_free = strbuf_detach(buf, NULL);
|
||||||
*/
|
|
||||||
nsize = size + stats.lf - stats.crlf;
|
|
||||||
buffer = xmalloc(nsize);
|
|
||||||
*sizep = nsize;
|
|
||||||
last = 0;
|
|
||||||
|
|
||||||
dst = buffer;
|
strbuf_grow(buf, len + stats.lf - stats.crlf);
|
||||||
do {
|
for (;;) {
|
||||||
unsigned char c = *src++;
|
const char *nl = memchr(src, '\n', len);
|
||||||
if (c == '\n' && last != '\r')
|
if (!nl)
|
||||||
*dst++ = '\r';
|
break;
|
||||||
*dst++ = c;
|
if (nl > src && nl[-1] == '\r') {
|
||||||
last = c;
|
strbuf_add(buf, src, nl + 1 - src);
|
||||||
} while (--size);
|
} else {
|
||||||
|
strbuf_add(buf, src, nl - src);
|
||||||
|
strbuf_addstr(buf, "\r\n");
|
||||||
|
}
|
||||||
|
len -= nl + 1 - src;
|
||||||
|
src = nl + 1;
|
||||||
|
}
|
||||||
|
strbuf_add(buf, src, len);
|
||||||
|
|
||||||
return buffer;
|
free(to_free);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int filter_buffer(const char *path, const char *src,
|
static int filter_buffer(const char *path, const char *src,
|
||||||
@ -246,8 +237,8 @@ static int filter_buffer(const char *path, const char *src,
|
|||||||
return (write_err || status);
|
return (write_err || status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *apply_filter(const char *path, const char *src,
|
static int apply_filter(const char *path, const char *src, size_t len,
|
||||||
unsigned long *sizep, const char *cmd)
|
struct strbuf *dst, const char *cmd)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Create a pipeline to have the command filter the buffer's
|
* Create a pipeline to have the command filter the buffer's
|
||||||
@ -255,21 +246,19 @@ static char *apply_filter(const char *path, const char *src,
|
|||||||
*
|
*
|
||||||
* (child --> cmd) --> us
|
* (child --> cmd) --> us
|
||||||
*/
|
*/
|
||||||
const int SLOP = 4096;
|
|
||||||
int pipe_feed[2];
|
int pipe_feed[2];
|
||||||
int status;
|
int status, ret = 1;
|
||||||
char *dst;
|
|
||||||
unsigned long dstsize, dstalloc;
|
|
||||||
struct child_process child_process;
|
struct child_process child_process;
|
||||||
|
struct strbuf nbuf;
|
||||||
|
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
memset(&child_process, 0, sizeof(child_process));
|
memset(&child_process, 0, sizeof(child_process));
|
||||||
|
|
||||||
if (pipe(pipe_feed) < 0) {
|
if (pipe(pipe_feed) < 0) {
|
||||||
error("cannot create pipe to run external filter %s", cmd);
|
error("cannot create pipe to run external filter %s", cmd);
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fflush(NULL);
|
fflush(NULL);
|
||||||
@ -278,54 +267,36 @@ static char *apply_filter(const char *path, const char *src,
|
|||||||
error("cannot fork to run external filter %s", cmd);
|
error("cannot fork to run external filter %s", cmd);
|
||||||
close(pipe_feed[0]);
|
close(pipe_feed[0]);
|
||||||
close(pipe_feed[1]);
|
close(pipe_feed[1]);
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!child_process.pid) {
|
if (!child_process.pid) {
|
||||||
dup2(pipe_feed[1], 1);
|
dup2(pipe_feed[1], 1);
|
||||||
close(pipe_feed[0]);
|
close(pipe_feed[0]);
|
||||||
close(pipe_feed[1]);
|
close(pipe_feed[1]);
|
||||||
exit(filter_buffer(path, src, *sizep, cmd));
|
exit(filter_buffer(path, src, len, cmd));
|
||||||
}
|
}
|
||||||
close(pipe_feed[1]);
|
close(pipe_feed[1]);
|
||||||
|
|
||||||
dstalloc = *sizep;
|
strbuf_init(&nbuf, 0);
|
||||||
dst = xmalloc(dstalloc);
|
if (strbuf_read(&nbuf, pipe_feed[0], len) < 0) {
|
||||||
dstsize = 0;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
ssize_t numread = xread(pipe_feed[0], dst + dstsize,
|
|
||||||
dstalloc - dstsize);
|
|
||||||
|
|
||||||
if (numread <= 0) {
|
|
||||||
if (!numread)
|
|
||||||
break;
|
|
||||||
error("read from external filter %s failed", cmd);
|
error("read from external filter %s failed", cmd);
|
||||||
free(dst);
|
ret = 0;
|
||||||
dst = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dstsize += numread;
|
|
||||||
if (dstalloc <= dstsize + SLOP) {
|
|
||||||
dstalloc = dstsize + SLOP;
|
|
||||||
dst = xrealloc(dst, dstalloc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (close(pipe_feed[0])) {
|
if (close(pipe_feed[0])) {
|
||||||
error("read from external filter %s failed", cmd);
|
error("read from external filter %s failed", cmd);
|
||||||
free(dst);
|
ret = 0;
|
||||||
dst = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = finish_command(&child_process);
|
status = finish_command(&child_process);
|
||||||
if (status) {
|
if (status) {
|
||||||
error("external filter %s failed %d", cmd, -status);
|
error("external filter %s failed %d", cmd, -status);
|
||||||
free(dst);
|
ret = 0;
|
||||||
dst = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst)
|
if (ret) {
|
||||||
*sizep = dstsize;
|
strbuf_swap(dst, &nbuf);
|
||||||
return dst;
|
}
|
||||||
|
strbuf_release(&nbuf);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct convert_driver {
|
static struct convert_driver {
|
||||||
@ -353,13 +324,8 @@ static int read_convert_config(const char *var, const char *value)
|
|||||||
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
||||||
break;
|
break;
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
char *namebuf;
|
|
||||||
drv = xcalloc(1, sizeof(struct convert_driver));
|
drv = xcalloc(1, sizeof(struct convert_driver));
|
||||||
namebuf = xmalloc(namelen + 1);
|
drv->name = xmemdupz(name, namelen);
|
||||||
memcpy(namebuf, name, namelen);
|
|
||||||
namebuf[namelen] = 0;
|
|
||||||
drv->name = namebuf;
|
|
||||||
drv->next = NULL;
|
|
||||||
*user_convert_tail = drv;
|
*user_convert_tail = drv;
|
||||||
user_convert_tail = &(drv->next);
|
user_convert_tail = &(drv->next);
|
||||||
}
|
}
|
||||||
@ -449,137 +415,106 @@ static int count_ident(const char *cp, unsigned long size)
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ident_to_git(const char *path, const char *src, unsigned long *sizep, int ident)
|
static int ident_to_git(const char *path, const char *src, size_t len,
|
||||||
|
struct strbuf *buf, int ident)
|
||||||
{
|
{
|
||||||
int cnt;
|
char *dst, *dollar;
|
||||||
unsigned long size;
|
|
||||||
char *dst, *buf;
|
|
||||||
|
|
||||||
if (!ident)
|
if (!ident || !count_ident(src, len))
|
||||||
return NULL;
|
return 0;
|
||||||
size = *sizep;
|
|
||||||
cnt = count_ident(src, size);
|
|
||||||
if (!cnt)
|
|
||||||
return NULL;
|
|
||||||
buf = xmalloc(size);
|
|
||||||
|
|
||||||
for (dst = buf; size; size--) {
|
/* only grow if not in place */
|
||||||
char ch = *src++;
|
if (strbuf_avail(buf) + buf->len < len)
|
||||||
*dst++ = ch;
|
strbuf_grow(buf, len - buf->len);
|
||||||
if ((ch == '$') && (3 <= size) &&
|
dst = buf->buf;
|
||||||
!memcmp("Id:", src, 3)) {
|
for (;;) {
|
||||||
unsigned long rem = size - 3;
|
dollar = memchr(src, '$', len);
|
||||||
const char *cp = src + 3;
|
if (!dollar)
|
||||||
do {
|
break;
|
||||||
ch = *cp++;
|
memcpy(dst, src, dollar + 1 - src);
|
||||||
if (ch == '$')
|
dst += dollar + 1 - src;
|
||||||
|
len -= dollar + 1 - src;
|
||||||
|
src = dollar + 1;
|
||||||
|
|
||||||
|
if (len > 3 && !memcmp(src, "Id:", 3)) {
|
||||||
|
dollar = memchr(src + 3, '$', len - 3);
|
||||||
|
if (!dollar)
|
||||||
break;
|
break;
|
||||||
rem--;
|
|
||||||
} while (rem);
|
|
||||||
if (!rem)
|
|
||||||
continue;
|
|
||||||
memcpy(dst, "Id$", 3);
|
memcpy(dst, "Id$", 3);
|
||||||
dst += 3;
|
dst += 3;
|
||||||
size -= (cp - src);
|
len -= dollar + 1 - src;
|
||||||
src = cp;
|
src = dollar + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memcpy(dst, src, len);
|
||||||
*sizep = dst - buf;
|
strbuf_setlen(buf, dst + len - buf->buf);
|
||||||
return buf;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ident_to_worktree(const char *path, const char *src, unsigned long *sizep, int ident)
|
static int ident_to_worktree(const char *path, const char *src, size_t len,
|
||||||
|
struct strbuf *buf, int ident)
|
||||||
{
|
{
|
||||||
int cnt;
|
|
||||||
unsigned long size;
|
|
||||||
char *dst, *buf;
|
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
char *to_free = NULL, *dollar;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
if (!ident)
|
if (!ident)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
size = *sizep;
|
cnt = count_ident(src, len);
|
||||||
cnt = count_ident(src, size);
|
|
||||||
if (!cnt)
|
if (!cnt)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
hash_sha1_file(src, size, "blob", sha1);
|
/* are we "faking" in place editing ? */
|
||||||
buf = xmalloc(size + cnt * 43);
|
if (src == buf->buf)
|
||||||
|
to_free = strbuf_detach(buf, NULL);
|
||||||
|
hash_sha1_file(src, len, "blob", sha1);
|
||||||
|
|
||||||
for (dst = buf; size; size--) {
|
strbuf_grow(buf, len + cnt * 43);
|
||||||
const char *cp;
|
for (;;) {
|
||||||
/* Fetch next source character, move the pointer on */
|
/* step 1: run to the next '$' */
|
||||||
char ch = *src++;
|
dollar = memchr(src, '$', len);
|
||||||
/* Copy the current character to the destination */
|
if (!dollar)
|
||||||
*dst++ = ch;
|
break;
|
||||||
/* If the current character is "$" or there are less than three
|
strbuf_add(buf, src, dollar + 1 - src);
|
||||||
* remaining bytes or the two bytes following this one are not
|
len -= dollar + 1 - src;
|
||||||
* "Id", then simply read the next character */
|
src = dollar + 1;
|
||||||
if ((ch != '$') || (size < 3) || memcmp("Id", src, 2))
|
|
||||||
|
/* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
|
||||||
|
if (len < 3 || memcmp("Id", src, 2))
|
||||||
continue;
|
continue;
|
||||||
/*
|
|
||||||
* Here when
|
|
||||||
* - There are more than 2 bytes remaining
|
|
||||||
* - The current three bytes are "$Id"
|
|
||||||
* with
|
|
||||||
* - ch == "$"
|
|
||||||
* - src[0] == "I"
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* step 3: skip over Id$ or Id:xxxxx$ */
|
||||||
|
if (src[2] == '$') {
|
||||||
|
src += 3;
|
||||||
|
len -= 3;
|
||||||
|
} else if (src[2] == ':') {
|
||||||
/*
|
/*
|
||||||
* It's possible that an expanded Id has crept its way into the
|
* It's possible that an expanded Id has crept its way into the
|
||||||
* repository, we cope with that by stripping the expansion out
|
* repository, we cope with that by stripping the expansion out
|
||||||
*/
|
*/
|
||||||
if (src[2] == ':') {
|
dollar = memchr(src + 3, '$', len - 3);
|
||||||
/* Expanded keywords have "$Id:" at the front */
|
if (!dollar) {
|
||||||
|
/* incomplete keyword, no more '$', so just quit the loop */
|
||||||
/* discard up to but not including the closing $ */
|
|
||||||
unsigned long rem = size - 3;
|
|
||||||
/* Point at first byte after the ":" */
|
|
||||||
cp = src + 3;
|
|
||||||
/*
|
|
||||||
* Throw away characters until either
|
|
||||||
* - we reach a "$"
|
|
||||||
* - we run out of bytes (rem == 0)
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
ch = *cp;
|
|
||||||
if (ch == '$')
|
|
||||||
break;
|
break;
|
||||||
cp++;
|
|
||||||
rem--;
|
|
||||||
} while (rem);
|
|
||||||
/* If the above finished because it ran out of characters, then
|
|
||||||
* this is an incomplete keyword, so don't run the expansion */
|
|
||||||
if (!rem)
|
|
||||||
continue;
|
|
||||||
} else if (src[2] == '$')
|
|
||||||
cp = src + 2;
|
|
||||||
else
|
|
||||||
/* Anything other than "$Id:XXX$" or $Id$ and we skip the
|
|
||||||
* expansion */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* cp is now pointing at the last $ of the keyword */
|
|
||||||
|
|
||||||
memcpy(dst, "Id: ", 4);
|
|
||||||
dst += 4;
|
|
||||||
memcpy(dst, sha1_to_hex(sha1), 40);
|
|
||||||
dst += 40;
|
|
||||||
*dst++ = ' ';
|
|
||||||
|
|
||||||
/* Adjust for the characters we've discarded */
|
|
||||||
size -= (cp - src);
|
|
||||||
src = cp;
|
|
||||||
|
|
||||||
/* Copy the final "$" */
|
|
||||||
*dst++ = *src++;
|
|
||||||
size--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*sizep = dst - buf;
|
len -= dollar + 1 - src;
|
||||||
return buf;
|
src = dollar + 1;
|
||||||
|
} else {
|
||||||
|
/* it wasn't a "Id$" or "Id:xxxx$" */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* step 4: substitute */
|
||||||
|
strbuf_addstr(buf, "Id: ");
|
||||||
|
strbuf_add(buf, sha1_to_hex(sha1), 40);
|
||||||
|
strbuf_addstr(buf, " $");
|
||||||
|
}
|
||||||
|
strbuf_add(buf, src, len);
|
||||||
|
|
||||||
|
free(to_free);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int git_path_check_crlf(const char *path, struct git_attr_check *check)
|
static int git_path_check_crlf(const char *path, struct git_attr_check *check)
|
||||||
@ -618,13 +553,12 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
|
|||||||
return !!ATTR_TRUE(value);
|
return !!ATTR_TRUE(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *convert_to_git(const char *path, const char *src, unsigned long *sizep)
|
int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst)
|
||||||
{
|
{
|
||||||
struct git_attr_check check[3];
|
struct git_attr_check check[3];
|
||||||
int crlf = CRLF_GUESS;
|
int crlf = CRLF_GUESS;
|
||||||
int ident = 0;
|
int ident = 0, ret = 0;
|
||||||
char *filter = NULL;
|
char *filter = NULL;
|
||||||
char *buf, *buf2;
|
|
||||||
|
|
||||||
setup_convert_check(check);
|
setup_convert_check(check);
|
||||||
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
||||||
@ -636,30 +570,25 @@ char *convert_to_git(const char *path, const char *src, unsigned long *sizep)
|
|||||||
filter = drv->clean;
|
filter = drv->clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = apply_filter(path, src, sizep, filter);
|
ret |= apply_filter(path, src, len, dst, filter);
|
||||||
|
if (ret) {
|
||||||
buf2 = crlf_to_git(path, buf ? buf : src, sizep, crlf);
|
src = dst->buf;
|
||||||
if (buf2) {
|
len = dst->len;
|
||||||
free(buf);
|
|
||||||
buf = buf2;
|
|
||||||
}
|
}
|
||||||
|
ret |= crlf_to_git(path, src, len, dst, crlf);
|
||||||
buf2 = ident_to_git(path, buf ? buf : src, sizep, ident);
|
if (ret) {
|
||||||
if (buf2) {
|
src = dst->buf;
|
||||||
free(buf);
|
len = dst->len;
|
||||||
buf = buf2;
|
|
||||||
}
|
}
|
||||||
|
return ret | ident_to_git(path, src, len, dst, ident);
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep)
|
int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
|
||||||
{
|
{
|
||||||
struct git_attr_check check[3];
|
struct git_attr_check check[3];
|
||||||
int crlf = CRLF_GUESS;
|
int crlf = CRLF_GUESS;
|
||||||
int ident = 0;
|
int ident = 0, ret = 0;
|
||||||
char *filter = NULL;
|
char *filter = NULL;
|
||||||
char *buf, *buf2;
|
|
||||||
|
|
||||||
setup_convert_check(check);
|
setup_convert_check(check);
|
||||||
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
||||||
@ -671,19 +600,15 @@ char *convert_to_working_tree(const char *path, const char *src, unsigned long *
|
|||||||
filter = drv->smudge;
|
filter = drv->smudge;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = ident_to_worktree(path, src, sizep, ident);
|
ret |= ident_to_worktree(path, src, len, dst, ident);
|
||||||
|
if (ret) {
|
||||||
buf2 = crlf_to_worktree(path, buf ? buf : src, sizep, crlf);
|
src = dst->buf;
|
||||||
if (buf2) {
|
len = dst->len;
|
||||||
free(buf);
|
|
||||||
buf = buf2;
|
|
||||||
}
|
}
|
||||||
|
ret |= crlf_to_worktree(path, src, len, dst, crlf);
|
||||||
buf2 = apply_filter(path, buf ? buf : src, sizep, filter);
|
if (ret) {
|
||||||
if (buf2) {
|
src = dst->buf;
|
||||||
free(buf);
|
len = dst->len;
|
||||||
buf = buf2;
|
|
||||||
}
|
}
|
||||||
|
return ret | apply_filter(path, src, len, dst, filter);
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
20
date.c
20
date.c
@ -584,6 +584,26 @@ int parse_date(const char *date, char *result, int maxlen)
|
|||||||
return date_string(then, offset, result, maxlen);
|
return date_string(then, offset, result, maxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum date_mode parse_date_format(const char *format)
|
||||||
|
{
|
||||||
|
if (!strcmp(format, "relative"))
|
||||||
|
return DATE_RELATIVE;
|
||||||
|
else if (!strcmp(format, "iso8601") ||
|
||||||
|
!strcmp(format, "iso"))
|
||||||
|
return DATE_ISO8601;
|
||||||
|
else if (!strcmp(format, "rfc2822") ||
|
||||||
|
!strcmp(format, "rfc"))
|
||||||
|
return DATE_RFC2822;
|
||||||
|
else if (!strcmp(format, "short"))
|
||||||
|
return DATE_SHORT;
|
||||||
|
else if (!strcmp(format, "local"))
|
||||||
|
return DATE_LOCAL;
|
||||||
|
else if (!strcmp(format, "default"))
|
||||||
|
return DATE_NORMAL;
|
||||||
|
else
|
||||||
|
die("unknown date format %s", format);
|
||||||
|
}
|
||||||
|
|
||||||
void datestamp(char *buf, int bufsize)
|
void datestamp(char *buf, int bufsize)
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
|
339
diff.c
339
diff.c
@ -83,13 +83,8 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
|
|||||||
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
||||||
break;
|
break;
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
char *namebuf;
|
|
||||||
drv = xcalloc(1, sizeof(struct ll_diff_driver));
|
drv = xcalloc(1, sizeof(struct ll_diff_driver));
|
||||||
namebuf = xmalloc(namelen + 1);
|
drv->name = xmemdupz(name, namelen);
|
||||||
memcpy(namebuf, name, namelen);
|
|
||||||
namebuf[namelen] = 0;
|
|
||||||
drv->name = namebuf;
|
|
||||||
drv->next = NULL;
|
|
||||||
if (!user_diff_tail)
|
if (!user_diff_tail)
|
||||||
user_diff_tail = &user_diff;
|
user_diff_tail = &user_diff;
|
||||||
*user_diff_tail = drv;
|
*user_diff_tail = drv;
|
||||||
@ -126,12 +121,8 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v
|
|||||||
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
|
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
|
||||||
break;
|
break;
|
||||||
if (!pp) {
|
if (!pp) {
|
||||||
char *namebuf;
|
|
||||||
pp = xcalloc(1, sizeof(*pp));
|
pp = xcalloc(1, sizeof(*pp));
|
||||||
namebuf = xmalloc(namelen + 1);
|
pp->name = xmemdupz(name, namelen);
|
||||||
memcpy(namebuf, name, namelen);
|
|
||||||
namebuf[namelen] = 0;
|
|
||||||
pp->name = namebuf;
|
|
||||||
pp->next = funcname_pattern_list;
|
pp->next = funcname_pattern_list;
|
||||||
funcname_pattern_list = pp;
|
funcname_pattern_list = pp;
|
||||||
}
|
}
|
||||||
@ -190,44 +181,23 @@ int git_diff_ui_config(const char *var, const char *value)
|
|||||||
return git_default_config(var, value);
|
return git_default_config(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *quote_one(const char *str)
|
|
||||||
{
|
|
||||||
int needlen;
|
|
||||||
char *xp;
|
|
||||||
|
|
||||||
if (!str)
|
|
||||||
return NULL;
|
|
||||||
needlen = quote_c_style(str, NULL, NULL, 0);
|
|
||||||
if (!needlen)
|
|
||||||
return xstrdup(str);
|
|
||||||
xp = xmalloc(needlen + 1);
|
|
||||||
quote_c_style(str, xp, NULL, 0);
|
|
||||||
return xp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *quote_two(const char *one, const char *two)
|
static char *quote_two(const char *one, const char *two)
|
||||||
{
|
{
|
||||||
int need_one = quote_c_style(one, NULL, NULL, 1);
|
int need_one = quote_c_style(one, NULL, NULL, 1);
|
||||||
int need_two = quote_c_style(two, NULL, NULL, 1);
|
int need_two = quote_c_style(two, NULL, NULL, 1);
|
||||||
char *xp;
|
struct strbuf res;
|
||||||
|
|
||||||
|
strbuf_init(&res, 0);
|
||||||
if (need_one + need_two) {
|
if (need_one + need_two) {
|
||||||
if (!need_one) need_one = strlen(one);
|
strbuf_addch(&res, '"');
|
||||||
if (!need_two) need_one = strlen(two);
|
quote_c_style(one, &res, NULL, 1);
|
||||||
|
quote_c_style(two, &res, NULL, 1);
|
||||||
xp = xmalloc(need_one + need_two + 3);
|
strbuf_addch(&res, '"');
|
||||||
xp[0] = '"';
|
} else {
|
||||||
quote_c_style(one, xp + 1, NULL, 1);
|
strbuf_addstr(&res, one);
|
||||||
quote_c_style(two, xp + need_one + 1, NULL, 1);
|
strbuf_addstr(&res, two);
|
||||||
strcpy(xp + need_one + need_two + 1, "\"");
|
|
||||||
return xp;
|
|
||||||
}
|
}
|
||||||
need_one = strlen(one);
|
return strbuf_detach(&res, NULL);
|
||||||
need_two = strlen(two);
|
|
||||||
xp = xmalloc(need_one + need_two + 1);
|
|
||||||
strcpy(xp, one);
|
|
||||||
strcpy(xp + need_one, two);
|
|
||||||
return xp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *external_diff(void)
|
static const char *external_diff(void)
|
||||||
@ -679,27 +649,20 @@ static char *pprint_rename(const char *a, const char *b)
|
|||||||
{
|
{
|
||||||
const char *old = a;
|
const char *old = a;
|
||||||
const char *new = b;
|
const char *new = b;
|
||||||
char *name = NULL;
|
struct strbuf name;
|
||||||
int pfx_length, sfx_length;
|
int pfx_length, sfx_length;
|
||||||
int len_a = strlen(a);
|
int len_a = strlen(a);
|
||||||
int len_b = strlen(b);
|
int len_b = strlen(b);
|
||||||
|
int a_midlen, b_midlen;
|
||||||
int qlen_a = quote_c_style(a, NULL, NULL, 0);
|
int qlen_a = quote_c_style(a, NULL, NULL, 0);
|
||||||
int qlen_b = quote_c_style(b, NULL, NULL, 0);
|
int qlen_b = quote_c_style(b, NULL, NULL, 0);
|
||||||
|
|
||||||
|
strbuf_init(&name, 0);
|
||||||
if (qlen_a || qlen_b) {
|
if (qlen_a || qlen_b) {
|
||||||
if (qlen_a) len_a = qlen_a;
|
quote_c_style(a, &name, NULL, 0);
|
||||||
if (qlen_b) len_b = qlen_b;
|
strbuf_addstr(&name, " => ");
|
||||||
name = xmalloc( len_a + len_b + 5 );
|
quote_c_style(b, &name, NULL, 0);
|
||||||
if (qlen_a)
|
return strbuf_detach(&name, NULL);
|
||||||
quote_c_style(a, name, NULL, 0);
|
|
||||||
else
|
|
||||||
memcpy(name, a, len_a);
|
|
||||||
memcpy(name + len_a, " => ", 4);
|
|
||||||
if (qlen_b)
|
|
||||||
quote_c_style(b, name + len_a + 4, NULL, 0);
|
|
||||||
else
|
|
||||||
memcpy(name + len_a + 4, b, len_b + 1);
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find common prefix */
|
/* Find common prefix */
|
||||||
@ -728,24 +691,26 @@ static char *pprint_rename(const char *a, const char *b)
|
|||||||
* pfx{sfx-a => sfx-b}
|
* pfx{sfx-a => sfx-b}
|
||||||
* name-a => name-b
|
* name-a => name-b
|
||||||
*/
|
*/
|
||||||
if (pfx_length + sfx_length) {
|
a_midlen = len_a - pfx_length - sfx_length;
|
||||||
int a_midlen = len_a - pfx_length - sfx_length;
|
b_midlen = len_b - pfx_length - sfx_length;
|
||||||
int b_midlen = len_b - pfx_length - sfx_length;
|
if (a_midlen < 0)
|
||||||
if (a_midlen < 0) a_midlen = 0;
|
a_midlen = 0;
|
||||||
if (b_midlen < 0) b_midlen = 0;
|
if (b_midlen < 0)
|
||||||
|
b_midlen = 0;
|
||||||
|
|
||||||
name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7);
|
strbuf_grow(&name, pfx_length + a_midlen + b_midlen + sfx_length + 7);
|
||||||
sprintf(name, "%.*s{%.*s => %.*s}%s",
|
if (pfx_length + sfx_length) {
|
||||||
pfx_length, a,
|
strbuf_add(&name, a, pfx_length);
|
||||||
a_midlen, a + pfx_length,
|
strbuf_addch(&name, '{');
|
||||||
b_midlen, b + pfx_length,
|
|
||||||
a + len_a - sfx_length);
|
|
||||||
}
|
}
|
||||||
else {
|
strbuf_add(&name, a + pfx_length, a_midlen);
|
||||||
name = xmalloc(len_a + len_b + 5);
|
strbuf_addstr(&name, " => ");
|
||||||
sprintf(name, "%s => %s", a, b);
|
strbuf_add(&name, b + pfx_length, b_midlen);
|
||||||
|
if (pfx_length + sfx_length) {
|
||||||
|
strbuf_addch(&name, '}');
|
||||||
|
strbuf_add(&name, a + len_a - sfx_length, sfx_length);
|
||||||
}
|
}
|
||||||
return name;
|
return strbuf_detach(&name, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct diffstat_t {
|
struct diffstat_t {
|
||||||
@ -858,12 +823,13 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
|||||||
int change = file->added + file->deleted;
|
int change = file->added + file->deleted;
|
||||||
|
|
||||||
if (!file->is_renamed) { /* renames are already quoted by pprint_rename */
|
if (!file->is_renamed) { /* renames are already quoted by pprint_rename */
|
||||||
len = quote_c_style(file->name, NULL, NULL, 0);
|
struct strbuf buf;
|
||||||
if (len) {
|
strbuf_init(&buf, 0);
|
||||||
char *qname = xmalloc(len + 1);
|
if (quote_c_style(file->name, &buf, NULL, 0)) {
|
||||||
quote_c_style(file->name, qname, NULL, 0);
|
|
||||||
free(file->name);
|
free(file->name);
|
||||||
file->name = qname;
|
file->name = strbuf_detach(&buf, NULL);
|
||||||
|
} else {
|
||||||
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1001,13 +967,13 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
|
|||||||
printf("-\t-\t");
|
printf("-\t-\t");
|
||||||
else
|
else
|
||||||
printf("%d\t%d\t", file->added, file->deleted);
|
printf("%d\t%d\t", file->added, file->deleted);
|
||||||
if (options->line_termination && !file->is_renamed &&
|
if (!file->is_renamed) {
|
||||||
quote_c_style(file->name, NULL, NULL, 0))
|
write_name_quoted(file->name, stdout, options->line_termination);
|
||||||
quote_c_style(file->name, NULL, stdout, 0);
|
} else {
|
||||||
else
|
|
||||||
fputs(file->name, stdout);
|
fputs(file->name, stdout);
|
||||||
putchar(options->line_termination);
|
putchar(options->line_termination);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct checkdiff_t {
|
struct checkdiff_t {
|
||||||
@ -1545,26 +1511,15 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
|
|||||||
|
|
||||||
static int populate_from_stdin(struct diff_filespec *s)
|
static int populate_from_stdin(struct diff_filespec *s)
|
||||||
{
|
{
|
||||||
#define INCREMENT 1024
|
struct strbuf buf;
|
||||||
char *buf;
|
|
||||||
unsigned long size;
|
|
||||||
ssize_t got;
|
|
||||||
|
|
||||||
size = 0;
|
strbuf_init(&buf, 0);
|
||||||
buf = NULL;
|
if (strbuf_read(&buf, 0, 0) < 0)
|
||||||
while (1) {
|
|
||||||
buf = xrealloc(buf, size + INCREMENT);
|
|
||||||
got = xread(0, buf + size, INCREMENT);
|
|
||||||
if (!got)
|
|
||||||
break; /* EOF */
|
|
||||||
if (got < 0)
|
|
||||||
return error("error while reading from stdin %s",
|
return error("error while reading from stdin %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
size += got;
|
|
||||||
}
|
|
||||||
s->should_munmap = 0;
|
s->should_munmap = 0;
|
||||||
s->data = buf;
|
s->data = strbuf_detach(&buf, &s->size);
|
||||||
s->size = size;
|
|
||||||
s->should_free = 1;
|
s->should_free = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1609,10 +1564,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
|||||||
|
|
||||||
if (!s->sha1_valid ||
|
if (!s->sha1_valid ||
|
||||||
reuse_worktree_file(s->path, s->sha1, 0)) {
|
reuse_worktree_file(s->path, s->sha1, 0)) {
|
||||||
|
struct strbuf buf;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int fd;
|
int fd;
|
||||||
char *buf;
|
|
||||||
unsigned long size;
|
|
||||||
|
|
||||||
if (!strcmp(s->path, "-"))
|
if (!strcmp(s->path, "-"))
|
||||||
return populate_from_stdin(s);
|
return populate_from_stdin(s);
|
||||||
@ -1653,13 +1607,11 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
|||||||
/*
|
/*
|
||||||
* Convert from working tree format to canonical git format
|
* Convert from working tree format to canonical git format
|
||||||
*/
|
*/
|
||||||
size = s->size;
|
strbuf_init(&buf, 0);
|
||||||
buf = convert_to_git(s->path, s->data, &size);
|
if (convert_to_git(s->path, s->data, s->size, &buf)) {
|
||||||
if (buf) {
|
|
||||||
munmap(s->data, s->size);
|
munmap(s->data, s->size);
|
||||||
s->should_munmap = 0;
|
s->should_munmap = 0;
|
||||||
s->data = buf;
|
s->data = strbuf_detach(&buf, &s->size);
|
||||||
s->size = size;
|
|
||||||
s->should_free = 1;
|
s->should_free = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1675,7 +1627,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void diff_free_filespec_data(struct diff_filespec *s)
|
void diff_free_filespec_blob(struct diff_filespec *s)
|
||||||
{
|
{
|
||||||
if (s->should_free)
|
if (s->should_free)
|
||||||
free(s->data);
|
free(s->data);
|
||||||
@ -1686,6 +1638,11 @@ void diff_free_filespec_data(struct diff_filespec *s)
|
|||||||
s->should_free = s->should_munmap = 0;
|
s->should_free = s->should_munmap = 0;
|
||||||
s->data = NULL;
|
s->data = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void diff_free_filespec_data(struct diff_filespec *s)
|
||||||
|
{
|
||||||
|
diff_free_filespec_blob(s);
|
||||||
free(s->cnt_data);
|
free(s->cnt_data);
|
||||||
s->cnt_data = NULL;
|
s->cnt_data = NULL;
|
||||||
}
|
}
|
||||||
@ -1962,50 +1919,46 @@ static int similarity_index(struct diff_filepair *p)
|
|||||||
static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
||||||
{
|
{
|
||||||
const char *pgm = external_diff();
|
const char *pgm = external_diff();
|
||||||
char msg[PATH_MAX*2+300], *xfrm_msg;
|
struct strbuf msg;
|
||||||
struct diff_filespec *one;
|
char *xfrm_msg;
|
||||||
struct diff_filespec *two;
|
struct diff_filespec *one = p->one;
|
||||||
|
struct diff_filespec *two = p->two;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *other;
|
const char *other;
|
||||||
char *name_munged, *other_munged;
|
|
||||||
int complete_rewrite = 0;
|
int complete_rewrite = 0;
|
||||||
int len;
|
|
||||||
|
|
||||||
if (DIFF_PAIR_UNMERGED(p)) {
|
if (DIFF_PAIR_UNMERGED(p)) {
|
||||||
/* unmerged */
|
|
||||||
run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
|
run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = p->one->path;
|
name = p->one->path;
|
||||||
other = (strcmp(name, p->two->path) ? p->two->path : NULL);
|
other = (strcmp(name, p->two->path) ? p->two->path : NULL);
|
||||||
name_munged = quote_one(name);
|
|
||||||
other_munged = quote_one(other);
|
|
||||||
one = p->one; two = p->two;
|
|
||||||
|
|
||||||
diff_fill_sha1_info(one);
|
diff_fill_sha1_info(one);
|
||||||
diff_fill_sha1_info(two);
|
diff_fill_sha1_info(two);
|
||||||
|
|
||||||
len = 0;
|
strbuf_init(&msg, PATH_MAX * 2 + 300);
|
||||||
switch (p->status) {
|
switch (p->status) {
|
||||||
case DIFF_STATUS_COPIED:
|
case DIFF_STATUS_COPIED:
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
strbuf_addf(&msg, "similarity index %d%%", similarity_index(p));
|
||||||
"similarity index %d%%\n"
|
strbuf_addstr(&msg, "\ncopy from ");
|
||||||
"copy from %s\n"
|
quote_c_style(name, &msg, NULL, 0);
|
||||||
"copy to %s\n",
|
strbuf_addstr(&msg, "\ncopy to ");
|
||||||
similarity_index(p), name_munged, other_munged);
|
quote_c_style(other, &msg, NULL, 0);
|
||||||
|
strbuf_addch(&msg, '\n');
|
||||||
break;
|
break;
|
||||||
case DIFF_STATUS_RENAMED:
|
case DIFF_STATUS_RENAMED:
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
strbuf_addf(&msg, "similarity index %d%%", similarity_index(p));
|
||||||
"similarity index %d%%\n"
|
strbuf_addstr(&msg, "\nrename from ");
|
||||||
"rename from %s\n"
|
quote_c_style(name, &msg, NULL, 0);
|
||||||
"rename to %s\n",
|
strbuf_addstr(&msg, "\nrename to ");
|
||||||
similarity_index(p), name_munged, other_munged);
|
quote_c_style(other, &msg, NULL, 0);
|
||||||
|
strbuf_addch(&msg, '\n');
|
||||||
break;
|
break;
|
||||||
case DIFF_STATUS_MODIFIED:
|
case DIFF_STATUS_MODIFIED:
|
||||||
if (p->score) {
|
if (p->score) {
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
strbuf_addf(&msg, "dissimilarity index %d%%\n",
|
||||||
"dissimilarity index %d%%\n",
|
|
||||||
similarity_index(p));
|
similarity_index(p));
|
||||||
complete_rewrite = 1;
|
complete_rewrite = 1;
|
||||||
break;
|
break;
|
||||||
@ -2025,19 +1978,17 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
|||||||
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
|
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
|
||||||
abbrev = 40;
|
abbrev = 40;
|
||||||
}
|
}
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
strbuf_addf(&msg, "index %.*s..%.*s",
|
||||||
"index %.*s..%.*s",
|
|
||||||
abbrev, sha1_to_hex(one->sha1),
|
abbrev, sha1_to_hex(one->sha1),
|
||||||
abbrev, sha1_to_hex(two->sha1));
|
abbrev, sha1_to_hex(two->sha1));
|
||||||
if (one->mode == two->mode)
|
if (one->mode == two->mode)
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
strbuf_addf(&msg, " %06o", one->mode);
|
||||||
" %06o", one->mode);
|
strbuf_addch(&msg, '\n');
|
||||||
len += snprintf(msg + len, sizeof(msg) - len, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len)
|
if (msg.len)
|
||||||
msg[--len] = 0;
|
strbuf_setlen(&msg, msg.len - 1);
|
||||||
xfrm_msg = len ? msg : NULL;
|
xfrm_msg = msg.len ? msg.buf : NULL;
|
||||||
|
|
||||||
if (!pgm &&
|
if (!pgm &&
|
||||||
DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
|
DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
|
||||||
@ -2056,8 +2007,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
|||||||
run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
|
run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
|
||||||
complete_rewrite);
|
complete_rewrite);
|
||||||
|
|
||||||
free(name_munged);
|
strbuf_release(&msg);
|
||||||
free(other_munged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
|
static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
|
||||||
@ -2513,72 +2463,30 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len)
|
|||||||
return sha1_to_hex(sha1);
|
return sha1_to_hex(sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void diff_flush_raw(struct diff_filepair *p,
|
static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt)
|
||||||
struct diff_options *options)
|
|
||||||
{
|
{
|
||||||
int two_paths;
|
int line_termination = opt->line_termination;
|
||||||
char status[10];
|
int inter_name_termination = line_termination ? '\t' : '\0';
|
||||||
int abbrev = options->abbrev;
|
|
||||||
const char *path_one, *path_two;
|
|
||||||
int inter_name_termination = '\t';
|
|
||||||
int line_termination = options->line_termination;
|
|
||||||
|
|
||||||
if (!line_termination)
|
if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) {
|
||||||
inter_name_termination = 0;
|
printf(":%06o %06o %s ", p->one->mode, p->two->mode,
|
||||||
|
diff_unique_abbrev(p->one->sha1, opt->abbrev));
|
||||||
path_one = p->one->path;
|
printf("%s ", diff_unique_abbrev(p->two->sha1, opt->abbrev));
|
||||||
path_two = p->two->path;
|
}
|
||||||
if (line_termination) {
|
if (p->score) {
|
||||||
path_one = quote_one(path_one);
|
printf("%c%03d%c", p->status, similarity_index(p),
|
||||||
path_two = quote_one(path_two);
|
inter_name_termination);
|
||||||
|
} else {
|
||||||
|
printf("%c%c", p->status, inter_name_termination);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->score)
|
if (p->status == DIFF_STATUS_COPIED || p->status == DIFF_STATUS_RENAMED) {
|
||||||
sprintf(status, "%c%03d", p->status, similarity_index(p));
|
write_name_quoted(p->one->path, stdout, inter_name_termination);
|
||||||
else {
|
write_name_quoted(p->two->path, stdout, line_termination);
|
||||||
status[0] = p->status;
|
} else {
|
||||||
status[1] = 0;
|
const char *path = p->one->mode ? p->one->path : p->two->path;
|
||||||
|
write_name_quoted(path, stdout, line_termination);
|
||||||
}
|
}
|
||||||
switch (p->status) {
|
|
||||||
case DIFF_STATUS_COPIED:
|
|
||||||
case DIFF_STATUS_RENAMED:
|
|
||||||
two_paths = 1;
|
|
||||||
break;
|
|
||||||
case DIFF_STATUS_ADDED:
|
|
||||||
case DIFF_STATUS_DELETED:
|
|
||||||
two_paths = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
two_paths = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!(options->output_format & DIFF_FORMAT_NAME_STATUS)) {
|
|
||||||
printf(":%06o %06o %s ",
|
|
||||||
p->one->mode, p->two->mode,
|
|
||||||
diff_unique_abbrev(p->one->sha1, abbrev));
|
|
||||||
printf("%s ",
|
|
||||||
diff_unique_abbrev(p->two->sha1, abbrev));
|
|
||||||
}
|
|
||||||
printf("%s%c%s", status, inter_name_termination,
|
|
||||||
two_paths || p->one->mode ? path_one : path_two);
|
|
||||||
if (two_paths)
|
|
||||||
printf("%c%s", inter_name_termination, path_two);
|
|
||||||
putchar(line_termination);
|
|
||||||
if (path_one != p->one->path)
|
|
||||||
free((void*)path_one);
|
|
||||||
if (path_two != p->two->path)
|
|
||||||
free((void*)path_two);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void diff_flush_name(struct diff_filepair *p, struct diff_options *opt)
|
|
||||||
{
|
|
||||||
char *path = p->two->path;
|
|
||||||
|
|
||||||
if (opt->line_termination)
|
|
||||||
path = quote_one(p->two->path);
|
|
||||||
printf("%s%c", path, opt->line_termination);
|
|
||||||
if (p->two->path != path)
|
|
||||||
free(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int diff_unmodified_pair(struct diff_filepair *p)
|
int diff_unmodified_pair(struct diff_filepair *p)
|
||||||
@ -2588,14 +2496,11 @@ int diff_unmodified_pair(struct diff_filepair *p)
|
|||||||
* let transformers to produce diff_filepairs any way they want,
|
* let transformers to produce diff_filepairs any way they want,
|
||||||
* and filter and clean them up here before producing the output.
|
* and filter and clean them up here before producing the output.
|
||||||
*/
|
*/
|
||||||
struct diff_filespec *one, *two;
|
struct diff_filespec *one = p->one, *two = p->two;
|
||||||
|
|
||||||
if (DIFF_PAIR_UNMERGED(p))
|
if (DIFF_PAIR_UNMERGED(p))
|
||||||
return 0; /* unmerged is interesting */
|
return 0; /* unmerged is interesting */
|
||||||
|
|
||||||
one = p->one;
|
|
||||||
two = p->two;
|
|
||||||
|
|
||||||
/* deletion, addition, mode or type change
|
/* deletion, addition, mode or type change
|
||||||
* and rename are all interesting.
|
* and rename are all interesting.
|
||||||
*/
|
*/
|
||||||
@ -2784,32 +2689,27 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
|
|||||||
else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
|
else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
|
||||||
diff_flush_raw(p, opt);
|
diff_flush_raw(p, opt);
|
||||||
else if (fmt & DIFF_FORMAT_NAME)
|
else if (fmt & DIFF_FORMAT_NAME)
|
||||||
diff_flush_name(p, opt);
|
write_name_quoted(p->two->path, stdout, opt->line_termination);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
|
static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
|
||||||
{
|
{
|
||||||
char *name = quote_one(fs->path);
|
|
||||||
if (fs->mode)
|
if (fs->mode)
|
||||||
printf(" %s mode %06o %s\n", newdelete, fs->mode, name);
|
printf(" %s mode %06o ", newdelete, fs->mode);
|
||||||
else
|
else
|
||||||
printf(" %s %s\n", newdelete, name);
|
printf(" %s ", newdelete);
|
||||||
free(name);
|
write_name_quoted(fs->path, stdout, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void show_mode_change(struct diff_filepair *p, int show_name)
|
static void show_mode_change(struct diff_filepair *p, int show_name)
|
||||||
{
|
{
|
||||||
if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
|
if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
|
||||||
|
printf(" mode change %06o => %06o%c", p->one->mode, p->two->mode,
|
||||||
|
show_name ? ' ' : '\n');
|
||||||
if (show_name) {
|
if (show_name) {
|
||||||
char *name = quote_one(p->two->path);
|
write_name_quoted(p->two->path, stdout, '\n');
|
||||||
printf(" mode change %06o => %06o %s\n",
|
|
||||||
p->one->mode, p->two->mode, name);
|
|
||||||
free(name);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
printf(" mode change %06o => %06o\n",
|
|
||||||
p->one->mode, p->two->mode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2839,12 +2739,11 @@ static void diff_summary(struct diff_filepair *p)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (p->score) {
|
if (p->score) {
|
||||||
char *name = quote_one(p->two->path);
|
puts(" rewrite ");
|
||||||
printf(" rewrite %s (%d%%)\n", name,
|
write_name_quoted(p->two->path, stdout, ' ');
|
||||||
similarity_index(p));
|
printf("(%d%%)\n", similarity_index(p));
|
||||||
free(name);
|
}
|
||||||
show_mode_change(p, 0);
|
show_mode_change(p, !p->score);
|
||||||
} else show_mode_change(p, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,11 +48,8 @@ static void prepare_order(const char *orderfile)
|
|||||||
if (*ep == '\n') {
|
if (*ep == '\n') {
|
||||||
*ep = 0;
|
*ep = 0;
|
||||||
order[cnt] = cp;
|
order[cnt] = cp;
|
||||||
}
|
} else {
|
||||||
else {
|
order[cnt] = xmemdupz(cp, ep - cp);
|
||||||
order[cnt] = xmalloc(ep-cp+1);
|
|
||||||
memcpy(order[cnt], cp, ep-cp);
|
|
||||||
order[cnt][ep-cp] = 0;
|
|
||||||
}
|
}
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,8 @@ static int estimate_similarity(struct diff_filespec *src,
|
|||||||
if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
|
if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
|
if ((!src->cnt_data && diff_populate_filespec(src, 0))
|
||||||
|
|| (!dst->cnt_data && diff_populate_filespec(dst, 0)))
|
||||||
return 0; /* error but caught downstream */
|
return 0; /* error but caught downstream */
|
||||||
|
|
||||||
|
|
||||||
@ -377,10 +378,10 @@ void diffcore_rename(struct diff_options *options)
|
|||||||
m->score = estimate_similarity(one, two,
|
m->score = estimate_similarity(one, two,
|
||||||
minimum_score);
|
minimum_score);
|
||||||
m->name_score = basename_same(one, two);
|
m->name_score = basename_same(one, two);
|
||||||
diff_free_filespec_data(one);
|
diff_free_filespec_blob(one);
|
||||||
}
|
}
|
||||||
/* We do not need the text anymore */
|
/* We do not need the text anymore */
|
||||||
diff_free_filespec_data(two);
|
diff_free_filespec_blob(two);
|
||||||
dst_cnt++;
|
dst_cnt++;
|
||||||
}
|
}
|
||||||
/* cost matrix sorted by most to least similar pair */
|
/* cost matrix sorted by most to least similar pair */
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user