mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* whitespace=!indent,trail,space
|
||||
*.[ch] whitespace
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -50,7 +50,6 @@ git-gc
|
||||
git-get-tar-commit-id
|
||||
git-grep
|
||||
git-hash-object
|
||||
git-help--browse
|
||||
git-http-fetch
|
||||
git-http-push
|
||||
git-imap-send
|
||||
@@ -136,6 +135,7 @@ git-upload-pack
|
||||
git-var
|
||||
git-verify-pack
|
||||
git-verify-tag
|
||||
git-web--browse
|
||||
git-whatchanged
|
||||
git-write-tree
|
||||
git-core-*/?*
|
||||
|
||||
2
.mailmap
2
.mailmap
@@ -17,6 +17,7 @@ H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
|
||||
H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
|
||||
H. Peter Anvin <hpa@trantor.hos.anvin.org>
|
||||
Horst H. von Brand <vonbrand@inf.utfsm.cl>
|
||||
Jay Soffian <jaysoffian+git@gmail.com>
|
||||
Joachim Berdal Haga <cjhaga@fys.uio.no>
|
||||
Jon Loeliger <jdl@freescale.com>
|
||||
Jon Seymour <jon@blackcubes.dyndns.org>
|
||||
@@ -43,6 +44,7 @@ Steven Grimm <koreth@midwinter.com>
|
||||
Theodore Ts'o <tytso@mit.edu>
|
||||
Tony Luck <tony.luck@intel.com>
|
||||
Uwe Kleine-König <Uwe_Zeisberger@digi.com>
|
||||
Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
|
||||
Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
|
||||
Uwe Kleine-König <uzeisberger@io.fsforth.de>
|
||||
Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
|
||||
|
||||
1
Documentation/.gitattributes
vendored
Normal file
1
Documentation/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.txt whitespace
|
||||
@@ -45,6 +45,7 @@ man7dir=$(mandir)/man7
|
||||
|
||||
ASCIIDOC=asciidoc
|
||||
ASCIIDOC_EXTRA =
|
||||
MANPAGE_XSL = callouts.xsl
|
||||
INSTALL?=install
|
||||
RM ?= rm -f
|
||||
DOC_REF = origin/man
|
||||
@@ -65,6 +66,7 @@ ASCIIDOC_EXTRA += -a asciidoc7compatible
|
||||
endif
|
||||
ifdef DOCBOOK_XSL_172
|
||||
ASCIIDOC_EXTRA += -a docbook-xsl-172
|
||||
MANPAGE_XSL = manpage-1.72.xsl
|
||||
endif
|
||||
|
||||
#
|
||||
@@ -159,7 +161,7 @@ $(MAN_HTML): %.html : %.txt
|
||||
|
||||
%.1 %.5 %.7 : %.xml
|
||||
$(RM) $@
|
||||
xmlto -m callouts.xsl man $<
|
||||
xmlto -m $(MANPAGE_XSL) man $<
|
||||
|
||||
%.xml : %.txt
|
||||
$(RM) $@+ $@
|
||||
|
||||
17
Documentation/RelNotes-1.5.4.1.txt
Normal file
17
Documentation/RelNotes-1.5.4.1.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
GIT v1.5.4.1 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.4
|
||||
------------------
|
||||
|
||||
* "git-commit -C $tag" used to work but rewrite in C done in
|
||||
1.5.4 broke it.
|
||||
|
||||
* An entry in the .gitattributes file that names a pattern in a
|
||||
subdirectory of the directory it is in did not match
|
||||
correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
|
||||
match "a/b/foo.c" but it didn't).
|
||||
|
||||
* Customized color specification was parsed incorrectly when
|
||||
numeric color values are used. This was fixed in 1.5.4.1.
|
||||
|
||||
43
Documentation/RelNotes-1.5.4.2.txt
Normal file
43
Documentation/RelNotes-1.5.4.2.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
GIT v1.5.4.2 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.4
|
||||
------------------
|
||||
|
||||
* The configuration parser was not prepared to see string
|
||||
valued variables misspelled as boolean and segfaulted.
|
||||
|
||||
* Temporary files left behind due to interrupted object
|
||||
transfers were not cleaned up with "git prune".
|
||||
|
||||
* "git config --unset" was confused when the unset variables
|
||||
were spelled with continuation lines in the config file.
|
||||
|
||||
* The merge message detection in "git cvsimport" did not catch
|
||||
a message that began with "Merge...".
|
||||
|
||||
* "git status" suggests "git rm --cached" for unstaging the
|
||||
earlier "git add" before the initial commit.
|
||||
|
||||
* "git status" output was incorrect during a partial commit.
|
||||
|
||||
* "git bisect" refused to start when the HEAD was detached.
|
||||
|
||||
* "git bisect" allowed a wildcard character in the commit
|
||||
message expanded while writing its log file.
|
||||
|
||||
* Manual pages were not formatted correctly with docbook xsl
|
||||
1.72; added a workaround.
|
||||
|
||||
* "git-commit -C $tag" used to work but rewrite in C done in
|
||||
1.5.4 broke it. This was fixed in 1.5.4.1.
|
||||
|
||||
* An entry in the .gitattributes file that names a pattern in a
|
||||
subdirectory of the directory it is in did not match
|
||||
correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
|
||||
match "a/b/foo.c" but it didn't). This was fixed in 1.5.4.1.
|
||||
|
||||
* Customized color specification was parsed incorrectly when
|
||||
numeric color values are used. This was fixed in 1.5.4.1.
|
||||
|
||||
* http transport misbehaved when linked with curl-gnutls.
|
||||
78
Documentation/RelNotes-1.5.5.txt
Normal file
78
Documentation/RelNotes-1.5.5.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
GIT v1.5.5 Release Notes
|
||||
========================
|
||||
|
||||
Updates since v1.5.4
|
||||
--------------------
|
||||
|
||||
(performance)
|
||||
|
||||
* On platforms with suboptimal qsort(3) implementation, there
|
||||
is an option to use more reasonable substitute we ship with
|
||||
our software.
|
||||
|
||||
* New configuration variable "pack.packsizelimit" can be used
|
||||
in place of command line option --max-pack-size.
|
||||
|
||||
* "git fetch" over the native git protocol used to make a
|
||||
connection to find out the set of current remote refs and
|
||||
another to actually download the pack data. We now use only
|
||||
one connection for these tasks.
|
||||
|
||||
* "git commit" does not run lstat(2) more than necessary
|
||||
anymore.
|
||||
|
||||
(usability, bells and whistles)
|
||||
|
||||
* You can be warned when core.autocrlf conversion is applied in
|
||||
such a way that results in an irreversible conversion.
|
||||
|
||||
* A pattern "foo/" in .gitignore file now matches a directory
|
||||
"foo". Pattern "foo" also matches as before.
|
||||
|
||||
* "git describe" learned to limit the tags to be used for
|
||||
naming with --match option.
|
||||
|
||||
* "git describe --contains" now barfs when the named commit
|
||||
cannot be described.
|
||||
|
||||
* bash completion's prompt helper function can talk about
|
||||
operation in-progress (e.g. merge, rebase, etc.).
|
||||
|
||||
* "git commit" learned a new hook "prepare-commit-msg" that can
|
||||
inspect what is going to be committed and prepare the commit
|
||||
log message template to be edited.
|
||||
|
||||
* "git gui" learned an auto-spell checking.
|
||||
|
||||
* "git send-email" learned to prompt for passwords
|
||||
interactively.
|
||||
|
||||
* "git send-email" learned an easier way to suppress CC
|
||||
recipients.
|
||||
|
||||
* Various "git cvsimport", "git cvsexportcommit", "git svn" and
|
||||
"git p4" improvements.
|
||||
|
||||
(internal)
|
||||
|
||||
* Duplicated code between git-help and git-instaweb that
|
||||
launches user's preferred browser has been refactored.
|
||||
|
||||
* It is now easier to write test scripts that records known
|
||||
breakages.
|
||||
|
||||
|
||||
Fixes since v1.5.4
|
||||
------------------
|
||||
|
||||
All of the fixes in v1.5.4 maintenance series are included in
|
||||
this release, unless otherwise noted.
|
||||
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.4
|
||||
O=v1.5.4.2-122-g7cb97da
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -34,9 +34,9 @@ Checklist (and a short version for the impatient):
|
||||
- if your name is not writable in ASCII, make sure that
|
||||
you send off a message in the correct encoding.
|
||||
- send the patch to the list (git@vger.kernel.org) and the
|
||||
maintainer (gitster@pobox.com). If you use
|
||||
git-send-email(1), please test it first by sending
|
||||
email to yourself.
|
||||
maintainer (gitster@pobox.com) if (and only if) the patch
|
||||
is ready for inclusion. If you use git-send-email(1),
|
||||
please test it first by sending email to yourself.
|
||||
|
||||
Long version:
|
||||
|
||||
@@ -112,7 +112,12 @@ lose tabs that way if you are not careful.
|
||||
|
||||
It is a common convention to prefix your subject line with
|
||||
[PATCH]. This lets people easily distinguish patches from other
|
||||
e-mail discussions.
|
||||
e-mail discussions. Use of additional markers after PATCH and
|
||||
the closing bracket to mark the nature of the patch is also
|
||||
encouraged. E.g. [PATCH/RFC] is often used when the patch is
|
||||
not ready to be applied but it is for discussion, [PATCH v2],
|
||||
[PATCH v3] etc. are often seen when you are sending an update to
|
||||
what you have previously sent.
|
||||
|
||||
"git format-patch" command follows the best current practice to
|
||||
format the body of an e-mail message. At the beginning of the
|
||||
@@ -157,7 +162,8 @@ Note that your maintainer does not necessarily read everything
|
||||
on the git mailing list. If your patch is for discussion first,
|
||||
send it "To:" the mailing list, and optionally "cc:" him. If it
|
||||
is trivially correct or after the list reached a consensus, send
|
||||
it "To:" the maintainer and optionally "cc:" the list.
|
||||
it "To:" the maintainer and optionally "cc:" the list for
|
||||
inclusion.
|
||||
|
||||
Also note that your maintainer does not actively involve himself in
|
||||
maintaining what are in contrib/ hierarchy. When you send fixes and
|
||||
@@ -210,10 +216,53 @@ then you just add a line saying
|
||||
This line can be automatically added by git if you run the git-commit
|
||||
command with the -s option.
|
||||
|
||||
Some people also put extra tags at the end. They'll just be ignored for
|
||||
now, but you can do this to mark internal company procedures or just
|
||||
point out some special detail about the sign-off.
|
||||
Notice that you can place your own Signed-off-by: line when
|
||||
forwarding somebody else's patch with the above rules for
|
||||
D-C-O. Indeed you are encouraged to do so. Do not forget to
|
||||
place an in-body "From: " line at the beginning to properly attribute
|
||||
the change to its true author (see (2) above).
|
||||
|
||||
Some people also put extra tags at the end.
|
||||
|
||||
"Acked-by:" says that the patch was reviewed by the person who
|
||||
is more familiar with the issues and the area the patch attempts
|
||||
to modify. "Tested-by:" says the patch was tested by the person
|
||||
and found to have the desired effect.
|
||||
|
||||
------------------------------------------------
|
||||
An ideal patch flow
|
||||
|
||||
Here is an ideal patch flow for this project the current maintainer
|
||||
suggests to the contributors:
|
||||
|
||||
(0) You come up with an itch. You code it up.
|
||||
|
||||
(1) Send it to the list and cc people who may need to know about
|
||||
the change.
|
||||
|
||||
The people who may need to know are the ones whose code you
|
||||
are butchering. These people happen to be the ones who are
|
||||
most likely to be knowledgeable enough to help you, but
|
||||
they have no obligation to help you (i.e. you ask for help,
|
||||
don't demand). "git log -p -- $area_you_are_modifying" would
|
||||
help you find out who they are.
|
||||
|
||||
(2) You get comments and suggestions for improvements. You may
|
||||
even get them in a "on top of your change" patch form.
|
||||
|
||||
(3) Polish, refine, and re-send to the list and the people who
|
||||
spend their time to improve your patch. Go back to step (2).
|
||||
|
||||
(4) The list forms consensus that the last round of your patch is
|
||||
good. Send it to the list and cc the maintainer.
|
||||
|
||||
(5) A topic branch is created with the patch and is merged to 'next',
|
||||
and cooked further and eventually graduates to 'master'.
|
||||
|
||||
In any time between the (2)-(3) cycle, the maintainer may pick it up
|
||||
from the list and queue it to 'pu', in order to make it easier for
|
||||
people play with it without having to pick up and apply the patch to
|
||||
their trees themselves.
|
||||
|
||||
------------------------------------------------
|
||||
MUA specific hints
|
||||
|
||||
@@ -52,7 +52,7 @@ of lines before or after the line given by <start>.
|
||||
When <rev> is not specified, the command annotates the
|
||||
changes starting backwards from the working tree copy.
|
||||
This flag makes the command pretend as if the working
|
||||
tree copy has the contents of he named file (specify
|
||||
tree copy has the contents of the named file (specify
|
||||
`-` to make the command read from the standard input).
|
||||
|
||||
-M|<num>|::
|
||||
|
||||
@@ -139,6 +139,51 @@ core.autocrlf::
|
||||
"text" (i.e. be subjected to the autocrlf mechanism) is
|
||||
decided purely based on the contents.
|
||||
|
||||
core.safecrlf::
|
||||
If true, makes git check if converting `CRLF` as controlled by
|
||||
`core.autocrlf` is reversible. Git will verify if a command
|
||||
modifies a file in the work tree either directly or indirectly.
|
||||
For example, committing a file followed by checking out the
|
||||
same file should yield the original file in the work tree. If
|
||||
this is not the case for the current setting of
|
||||
`core.autocrlf`, git will reject the file. The variable can
|
||||
be set to "warn", in which case git will only warn about an
|
||||
irreversible conversion but continue the operation.
|
||||
+
|
||||
CRLF conversion bears a slight chance of corrupting data.
|
||||
autocrlf=true will convert CRLF to LF during commit and LF to
|
||||
CRLF during checkout. A file that contains a mixture of LF and
|
||||
CRLF before the commit cannot be recreated by git. For text
|
||||
files this is the right thing to do: it corrects line endings
|
||||
such that we have only LF line endings in the repository.
|
||||
But for binary files that are accidentally classified as text the
|
||||
conversion can corrupt data.
|
||||
+
|
||||
If you recognize such corruption early you can easily fix it by
|
||||
setting the conversion type explicitly in .gitattributes. Right
|
||||
after committing you still have the original file in your work
|
||||
tree and this file is not yet corrupted. You can explicitly tell
|
||||
git that this file is binary and git will handle the file
|
||||
appropriately.
|
||||
+
|
||||
Unfortunately, the desired effect of cleaning up text files with
|
||||
mixed line endings and the undesired effect of corrupting binary
|
||||
files cannot be distinguished. In both cases CRLFs are removed
|
||||
in an irreversible way. For text files this is the right thing
|
||||
to do because CRLFs are line endings, while for binary files
|
||||
converting CRLFs corrupts data.
|
||||
+
|
||||
Note, this safety check does not mean that a checkout will generate a
|
||||
file identical to the original file for a different setting of
|
||||
`core.autocrlf`, but only for the current one. For example, a text
|
||||
file with `LF` would be accepted with `core.autocrlf=input` and could
|
||||
later be checked out with `core.autocrlf=true`, in which case the
|
||||
resulting file would contain `CRLF`, although the original file
|
||||
contained `LF`. However, in both work trees the line endings would be
|
||||
consistent, that is either all `LF` or all `CRLF`, but never mixed. A
|
||||
file with mixed line endings would be reported by the `core.safecrlf`
|
||||
mechanism.
|
||||
|
||||
core.symlinks::
|
||||
If false, symbolic links are checked out as small plain files that
|
||||
contain the link text. linkgit:git-update-index[1] and
|
||||
@@ -333,7 +378,7 @@ branch.autosetupmerge::
|
||||
so that linkgit:git-pull[1] will appropriately merge from that
|
||||
remote branch. Note that even if this option is not set,
|
||||
this behavior can be chosen per-branch using the `--track`
|
||||
and `--no-track` options. This option defaults to false.
|
||||
and `--no-track` options. This option defaults to true.
|
||||
|
||||
branch.<name>.remote::
|
||||
When in branch <name>, it tells `git fetch` which remote to fetch.
|
||||
@@ -766,6 +811,12 @@ pack.indexVersion::
|
||||
whenever the corresponding pack is larger than 2 GB. Otherwise
|
||||
the default is 1.
|
||||
|
||||
pack.packSizeLimit:
|
||||
The default maximum size of a pack. This setting only affects
|
||||
packing to a file, i.e. the git:// protocol is unaffected. It
|
||||
can be overridden by the `\--max-pack-size` option of
|
||||
linkgit:git-repack[1].
|
||||
|
||||
pull.octopus::
|
||||
The default merge strategy to use when pulling multiple branches
|
||||
at once.
|
||||
|
||||
@@ -34,11 +34,11 @@ 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 sets up the
|
||||
branch so that linkgit:git-pull[1] will appropriately merge from that
|
||||
remote branch. If this behavior is desired, it is possible to make it
|
||||
the default using the global `branch.autosetupmerge` configuration
|
||||
flag. Otherwise, it can be chosen per-branch using the `--track`
|
||||
remote branch. If this behavior is not desired, it is possible to
|
||||
disable it using the global `branch.autosetupmerge` configuration
|
||||
flag. That setting can be overridden by using the `--track`
|
||||
and `--no-track` options.
|
||||
|
||||
With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
|
||||
@@ -108,10 +108,11 @@ OPTIONS
|
||||
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
|
||||
don't want to use "git pull <repository> <refspec>" explicitly.
|
||||
This behavior is the default. Set the
|
||||
branch.autosetupmerge configuration variable to false if you
|
||||
want git-checkout and git-branch to always behave as if
|
||||
'--track' were given.
|
||||
'--no-track' were given.
|
||||
|
||||
--no-track::
|
||||
When a branch is created off a remote branch,
|
||||
|
||||
@@ -52,10 +52,11 @@ OPTIONS
|
||||
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
|
||||
don't want to use "git pull <repository> <refspec>" explicitly.
|
||||
This behavior is the default. Set the
|
||||
branch.autosetupmerge configuration variable to false if you
|
||||
want git-checkout and git-branch to always behave as if
|
||||
'--track' were given.
|
||||
'--no-track' were given.
|
||||
|
||||
--no-track::
|
||||
When -b is given and a branch is created off a remote branch,
|
||||
|
||||
@@ -62,12 +62,13 @@ OPTIONS
|
||||
.git/objects/info/alternates to share the objects
|
||||
with the source repository. The resulting repository
|
||||
starts out without any object of its own.
|
||||
*NOTE*: this is a possibly dangerous operation; do *not* use
|
||||
it unless you understand what it does. If you clone your
|
||||
repository using this option, then delete branches in the
|
||||
source repository and then run linkgit:git-gc[1] using the
|
||||
'--prune' option in the source repository, it may remove
|
||||
objects which are referenced by the cloned repository.
|
||||
+
|
||||
*NOTE*: this is a possibly dangerous operation; do *not* use
|
||||
it unless you understand what it does. If you clone your
|
||||
repository using this option, then delete branches in the
|
||||
source repository and then run linkgit:git-gc[1] using the
|
||||
'--prune' option in the source repository, it may remove
|
||||
objects which are referenced by the cloned repository.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -280,8 +280,8 @@ order).
|
||||
|
||||
HOOKS
|
||||
-----
|
||||
This command can run `commit-msg`, `pre-commit`, and
|
||||
`post-commit` hooks. See link:hooks.html[hooks] for more
|
||||
This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`,
|
||||
and `post-commit` hooks. See link:hooks.html[hooks] for more
|
||||
information.
|
||||
|
||||
|
||||
|
||||
@@ -107,8 +107,8 @@ If you need to pass multiple options, separate them with a comma.
|
||||
|
||||
-M <regex>::
|
||||
Attempt to detect merges based on the commit message with a custom
|
||||
regex. It can be used with '-m' to also see the default regexes.
|
||||
You must escape forward slashes.
|
||||
regex. It can be used with '-m' to enable the default regexes
|
||||
as well. You must escape forward slashes.
|
||||
|
||||
-S <regex>::
|
||||
Skip paths matching the regex.
|
||||
|
||||
@@ -51,6 +51,10 @@ OPTIONS
|
||||
being employed to standard error. The tag name will still
|
||||
be printed to standard out.
|
||||
|
||||
--match <pattern>::
|
||||
Only consider tags matching the given pattern (can be used to avoid
|
||||
leaking private tags made from the repository).
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
||||
@@ -805,6 +805,93 @@ Placing a `progress` command immediately after a `checkpoint` will
|
||||
inform the reader when the `checkpoint` has been completed and it
|
||||
can safely access the refs that fast-import updated.
|
||||
|
||||
Crash Reports
|
||||
-------------
|
||||
If fast-import is supplied invalid input it will terminate with a
|
||||
non-zero exit status and create a crash report in the top level of
|
||||
the Git repository it was importing into. Crash reports contain
|
||||
a snapshot of the internal fast-import state as well as the most
|
||||
recent commands that lead up to the crash.
|
||||
|
||||
All recent commands (including stream comments, file changes and
|
||||
progress commands) are shown in the command history within the crash
|
||||
report, but raw file data and commit messages are excluded from the
|
||||
crash report. This exclusion saves space within the report file
|
||||
and reduces the amount of buffering that fast-import must perform
|
||||
during execution.
|
||||
|
||||
After writing a crash report fast-import will close the current
|
||||
packfile and export the marks table. This allows the frontend
|
||||
developer to inspect the repository state and resume the import from
|
||||
the point where it crashed. The modified branches and tags are not
|
||||
updated during a crash, as the import did not complete successfully.
|
||||
Branch and tag information can be found in the crash report and
|
||||
must be applied manually if the update is needed.
|
||||
|
||||
An example crash:
|
||||
|
||||
====
|
||||
$ cat >in <<END_OF_INPUT
|
||||
# my very first test commit
|
||||
commit refs/heads/master
|
||||
committer Shawn O. Pearce <spearce> 19283 -0400
|
||||
# who is that guy anyway?
|
||||
data <<EOF
|
||||
this is my commit
|
||||
EOF
|
||||
M 644 inline .gitignore
|
||||
data <<EOF
|
||||
.gitignore
|
||||
EOF
|
||||
M 777 inline bob
|
||||
END_OF_INPUT
|
||||
|
||||
$ git-fast-import <in
|
||||
fatal: Corrupt mode: M 777 inline bob
|
||||
fast-import: dumping crash report to .git/fast_import_crash_8434
|
||||
|
||||
$ cat .git/fast_import_crash_8434
|
||||
fast-import crash report:
|
||||
fast-import process: 8434
|
||||
parent process : 1391
|
||||
at Sat Sep 1 00:58:12 2007
|
||||
|
||||
fatal: Corrupt mode: M 777 inline bob
|
||||
|
||||
Most Recent Commands Before Crash
|
||||
---------------------------------
|
||||
# my very first test commit
|
||||
commit refs/heads/master
|
||||
committer Shawn O. Pearce <spearce> 19283 -0400
|
||||
# who is that guy anyway?
|
||||
data <<EOF
|
||||
M 644 inline .gitignore
|
||||
data <<EOF
|
||||
* M 777 inline bob
|
||||
|
||||
Active Branch LRU
|
||||
-----------------
|
||||
active_branches = 1 cur, 5 max
|
||||
|
||||
pos clock name
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
1) 0 refs/heads/master
|
||||
|
||||
Inactive Branches
|
||||
-----------------
|
||||
refs/heads/master:
|
||||
status : active loaded dirty
|
||||
tip commit : 0000000000000000000000000000000000000000
|
||||
old tree : 0000000000000000000000000000000000000000
|
||||
cur tree : 0000000000000000000000000000000000000000
|
||||
commit clock: 0
|
||||
last pack :
|
||||
|
||||
|
||||
-------------------
|
||||
END OF CRASH REPORT
|
||||
====
|
||||
|
||||
Tips and Tricks
|
||||
---------------
|
||||
The following tips and tricks have been collected from various
|
||||
|
||||
@@ -47,27 +47,9 @@ OPTIONS
|
||||
+
|
||||
The web browser can be specified using the configuration variable
|
||||
'help.browser', or 'web.browser' if the former is not set. If none of
|
||||
these config variables is set, the 'git-help--browse' helper script
|
||||
(called by 'git-help') will pick a suitable default.
|
||||
+
|
||||
You can explicitly provide a full path to your preferred browser by
|
||||
setting the configuration variable 'browser.<tool>.path'. For example,
|
||||
you can configure the absolute path to firefox by setting
|
||||
'browser.firefox.path'. Otherwise, 'git-help--browse' assumes the tool
|
||||
is available in PATH.
|
||||
+
|
||||
Note that the script tries, as much as possible, to display the HTML
|
||||
page in a new tab on an already opened browser.
|
||||
+
|
||||
The following browsers are currently supported by 'git-help--browse':
|
||||
+
|
||||
* firefox (this is the default under X Window when not using KDE)
|
||||
* iceweasel
|
||||
* konqueror (this is the default under KDE)
|
||||
* w3m (this is the default outside X Window)
|
||||
* links
|
||||
* lynx
|
||||
* dillo
|
||||
these config variables is set, the 'git-web--browse' helper script
|
||||
(called by 'git-help') will pick a suitable default. See
|
||||
linkgit:git-web--browse[1] for more information about this.
|
||||
|
||||
CONFIGURATION VARIABLES
|
||||
-----------------------
|
||||
@@ -84,7 +66,7 @@ line option:
|
||||
The 'help.browser', 'web.browser' and 'browser.<tool>.path' will also
|
||||
be checked if the 'web' format is chosen (either by command line
|
||||
option or configuration variable). See '-w|--web' in the OPTIONS
|
||||
section above.
|
||||
section above and linkgit:git-web--browse[1].
|
||||
|
||||
Note that these configuration variables should probably be set using
|
||||
the '--global' flag, for example like this:
|
||||
|
||||
@@ -38,10 +38,11 @@ OPTIONS
|
||||
The port number to bind the httpd to. (Default: 1234)
|
||||
|
||||
-b|--browser::
|
||||
|
||||
The web browser command-line to execute to view the gitweb page.
|
||||
If blank, the URL of the gitweb instance will be printed to
|
||||
stdout. (Default: 'firefox')
|
||||
The web browser that should be used to view the gitweb
|
||||
page. This will be passed to the 'git-web--browse' helper
|
||||
script along with the URL of the gitweb instance. See
|
||||
linkgit:git-web--browse[1] for more information about this. If
|
||||
the script fails, the URL will be printed to stdout.
|
||||
|
||||
--start::
|
||||
Start the httpd instance and exit. This does not generate
|
||||
@@ -72,7 +73,8 @@ You may specify configuration in your .git/config
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
If the configuration variable 'instaweb.browser' is not set,
|
||||
'web.browser' will be used instead if it is defined.
|
||||
'web.browser' will be used instead if it is defined. See
|
||||
linkgit:git-web--browse[1] for more information about this.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -99,7 +99,8 @@ base-name::
|
||||
--max-pack-size=<n>::
|
||||
Maximum size of each output packfile, expressed in MiB.
|
||||
If specified, multiple packfiles may be created.
|
||||
The default is unlimited.
|
||||
The default is unlimited, unless the config variable
|
||||
`pack.packSizeLimit` is set.
|
||||
|
||||
--incremental::
|
||||
This flag causes an object already in a pack ignored
|
||||
|
||||
@@ -39,11 +39,11 @@ include::merge-strategies.txt[]
|
||||
there is a remote ref for the upstream branch, and this branch
|
||||
was rebased since last fetched, the rebase uses that information
|
||||
to avoid rebasing non-local changes.
|
||||
|
||||
*NOTE:* This is a potentially _dangerous_ mode of operation.
|
||||
It rewrites history, which does not bode well when you
|
||||
published that history already. Do *not* use this option
|
||||
unless you have read linkgit:git-rebase[1] carefully.
|
||||
+
|
||||
*NOTE:* This is a potentially _dangerous_ mode of operation.
|
||||
It rewrites history, which does not bode well when you
|
||||
published that history already. Do *not* use this option
|
||||
unless you have read linkgit:git-rebase[1] carefully.
|
||||
|
||||
\--no-rebase::
|
||||
Override earlier \--rebase.
|
||||
|
||||
@@ -10,7 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-remote'
|
||||
'git-remote' add [-t <branch>] [-m <branch>] [-f] [--mirror] <name> <url>
|
||||
'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
||||
'git-remote' rm <name>
|
||||
'git-remote' show <name>
|
||||
'git-remote' prune <name>
|
||||
|
||||
@@ -8,8 +8,8 @@ git-reset - Reset current HEAD to the specified state
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-reset' [--mixed | --soft | --hard] [-q] [<commit>]
|
||||
'git-reset' [--mixed] [-q] [<commit>] [--] <paths>...
|
||||
'git reset' [--mixed | --soft | --hard] [-q] [<commit>]
|
||||
'git reset' [-q] [<commit>] [--] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -37,7 +37,7 @@ OPTIONS
|
||||
--soft::
|
||||
Does not touch the index file nor the working tree at all, but
|
||||
requires them to be in a good order. This leaves all your changed
|
||||
files "Added but not yet committed", as linkgit:git-status[1] would
|
||||
files "Changes to be committed", as linkgit:git-status[1] would
|
||||
put it.
|
||||
|
||||
--hard::
|
||||
@@ -176,6 +176,23 @@ $ git reset <3>
|
||||
committed as 'snapshot WIP'. This updates the index to show your
|
||||
WIP files as uncommitted.
|
||||
|
||||
Reset a single file in the index::
|
||||
+
|
||||
Suppose you have added a file to your index, but later decide you do not
|
||||
want to add it to your commit. You can remove the file from the index
|
||||
while keeping your changes with git reset.
|
||||
+
|
||||
------------
|
||||
$ git reset -- frotz.c <1>
|
||||
$ git commit -m "Commit files in index" <2>
|
||||
$ git add frotz.c <3>
|
||||
------------
|
||||
+
|
||||
<1> This removes the file from the index while keeping it in the working
|
||||
directory.
|
||||
<2> This commits all other changes in the index.
|
||||
<3> Adds the file to the index again.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net> and Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
@@ -96,11 +96,40 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
servers typically listen to smtp port 25 and ssmtp port
|
||||
465).
|
||||
|
||||
--smtp-user, --smtp-pass::
|
||||
Username and password for SMTP-AUTH. Defaults are the values of
|
||||
the configuration values 'sendemail.smtpuser' and
|
||||
'sendemail.smtppass', but see also 'sendemail.identity'.
|
||||
If not set, authentication is not attempted.
|
||||
--smtp-user::
|
||||
Username for SMTP-AUTH. In place of this option, the following
|
||||
configuration variables can be specified:
|
||||
+
|
||||
--
|
||||
* sendemail.smtpuser
|
||||
* sendemail.<identity>.smtpuser (see sendemail.identity).
|
||||
--
|
||||
+
|
||||
However, --smtp-user always overrides these variables.
|
||||
+
|
||||
If a username is not specified (with --smtp-user or a
|
||||
configuration variable), then authentication is not attempted.
|
||||
|
||||
--smtp-pass::
|
||||
Password for SMTP-AUTH. The argument is optional: If no
|
||||
argument is specified, then the empty string is used as
|
||||
the password.
|
||||
+
|
||||
In place of this option, the following configuration variables
|
||||
can be specified:
|
||||
+
|
||||
--
|
||||
* sendemail.smtppass
|
||||
* sendemail.<identity>.smtppass (see sendemail.identity).
|
||||
--
|
||||
+
|
||||
However, --smtp-pass always overrides these variables.
|
||||
+
|
||||
Furthermore, passwords need not be specified in configuration files
|
||||
or on the command line. If a username has been specified (with
|
||||
--smtp-user or a configuration variable), but no password has been
|
||||
specified (with --smtp-pass or a configuration variable), then the
|
||||
user is prompted for a password while the input is masked for privacy.
|
||||
|
||||
--smtp-ssl::
|
||||
If set, connects to the SMTP server using SSL.
|
||||
@@ -117,6 +146,17 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
Default is the value of 'sendemail.suppressfrom' configuration value;
|
||||
if that is unspecified, default to --no-suppress-from.
|
||||
|
||||
--suppress-cc::
|
||||
Specify an additional category of recipients to suppress the
|
||||
auto-cc of. 'self' will avoid including the sender, 'author' will
|
||||
avoid including the patch author, 'cc' will avoid including anyone
|
||||
mentioned in Cc lines in the patch, 'sob' will avoid including
|
||||
anyone mentioned in Signed-off-by lines, and 'cccmd' will avoid
|
||||
running the --cc-cmd. 'all' will suppress all auto cc values.
|
||||
Default is the value of 'sendemail.suppresscc' configuration value;
|
||||
if that is unspecified, default to 'self' if --suppress-from is
|
||||
specified, as well as 'sob' if --no-signed-off-cc is specified.
|
||||
|
||||
--thread, --no-thread::
|
||||
If this is set, the In-Reply-To header will be set on each email sent.
|
||||
If disabled with "--no-thread", no emails will have the In-Reply-To
|
||||
|
||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-stash' (list | show [<stash>] | apply [<stash>] | clear)
|
||||
'git-stash' [save] [message...]
|
||||
'git-stash' [save [<message>]]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -36,11 +36,12 @@ is also possible).
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
save::
|
||||
save [<message>]::
|
||||
|
||||
Save your local modifications to a new 'stash', and run `git-reset
|
||||
--hard` to revert them. This is the default action when no
|
||||
subcommand is given.
|
||||
subcommand is given. The <message> part is optional and gives
|
||||
the description along with the stashed state.
|
||||
|
||||
list::
|
||||
|
||||
|
||||
@@ -161,6 +161,13 @@ New features:
|
||||
+
|
||||
Any other arguments are passed directly to `git log'
|
||||
|
||||
'blame'::
|
||||
Show what revision and author last modified each line of a file. This is
|
||||
identical to `git blame', but SVN revision numbers are shown instead of git
|
||||
commit hashes.
|
||||
+
|
||||
All arguments are passed directly to `git blame'.
|
||||
|
||||
--
|
||||
'find-rev'::
|
||||
When given an SVN revision number of the form 'rN', returns the
|
||||
|
||||
78
Documentation/git-web--browse.txt
Normal file
78
Documentation/git-web--browse.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
git-web--browse(1)
|
||||
==================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-web--browse - git helper script to launch a web browser
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-web--browse' [OPTIONS] URL/FILE ...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This script tries, as much as possible, to display the URLs and FILEs
|
||||
that are passed as arguments, as HTML pages in new tabs on an already
|
||||
opened web browser.
|
||||
|
||||
The following browsers (or commands) are currently supported:
|
||||
|
||||
* firefox (this is the default under X Window when not using KDE)
|
||||
* iceweasel
|
||||
* konqueror (this is the default under KDE)
|
||||
* w3m (this is the default outside graphical environments)
|
||||
* links
|
||||
* lynx
|
||||
* dillo
|
||||
* open (this is the default under Mac OS X GUI)
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-b BROWSER|--browser=BROWSER::
|
||||
Use the specified BROWSER. It must be in the list of supported
|
||||
browsers.
|
||||
|
||||
-t BROWSER|--tool=BROWSER::
|
||||
Same as above.
|
||||
|
||||
-c CONF.VAR|--config=CONF.VAR::
|
||||
CONF.VAR is looked up in the git config files. If it's set,
|
||||
then its value specify the browser that should be used.
|
||||
|
||||
CONFIGURATION VARIABLES
|
||||
-----------------------
|
||||
|
||||
The web browser can be specified using a configuration variable passed
|
||||
with the -c (or --config) command line option, or the 'web.browser'
|
||||
configuration variable if the former is not used.
|
||||
|
||||
You can explicitly provide a full path to your preferred browser by
|
||||
setting the configuration variable 'browser.<tool>.path'. For example,
|
||||
you can configure the absolute path to firefox by setting
|
||||
'browser.firefox.path'. Otherwise, 'git-web--browse' assumes the tool
|
||||
is available in PATH.
|
||||
|
||||
Note that these configuration variables should probably be set using
|
||||
the '--global' flag, for example like this:
|
||||
|
||||
------------------------------------------------
|
||||
$ git config --global web.browser firefox
|
||||
------------------------------------------------
|
||||
|
||||
as they are probably more user specific than repository specific.
|
||||
See linkgit:git-config[1] for more information about this.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Christian Couder <chriscool@tuxfamily.org> and the git-list
|
||||
<git@vger.kernel.org>, based on git-mergetool by Theodore Y. Ts'o.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Documentation by Christian Couder <chriscool@tuxfamily.org> and the
|
||||
git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[7] suite
|
||||
@@ -43,6 +43,13 @@ unreleased) version of git, that is available from 'master'
|
||||
branch of the `git.git` repository.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v1.5.4.2/git.html[documentation for release 1.5.4.2]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.5.4.2.txt[1.5.4.2],
|
||||
link:RelNotes-1.5.4.1.txt[1.5.4.1],
|
||||
link:RelNotes-1.5.4.txt[1.5.4].
|
||||
|
||||
* link:v1.5.3.8/git.html[documentation for release 1.5.3.8]
|
||||
|
||||
* release notes for
|
||||
|
||||
@@ -133,6 +133,26 @@ When `core.autocrlf` is set to "input", line endings are
|
||||
converted to LF upon checkin, but there is no conversion done
|
||||
upon checkout.
|
||||
|
||||
If `core.safecrlf` is set to "true" or "warn", git verifies if
|
||||
the conversion is reversible for the current setting of
|
||||
`core.autocrlf`. For "true", git rejects irreversible
|
||||
conversions; for "warn", git only prints a warning but accepts
|
||||
an irreversible conversion. The safety triggers to prevent such
|
||||
a conversion done to the files in the work tree, but there are a
|
||||
few exceptions. Even though...
|
||||
|
||||
- "git add" itself does not touch the files in the work tree, the
|
||||
next checkout would, so the safety triggers;
|
||||
|
||||
- "git apply" to update a text file with a patch does touch the files
|
||||
in the work tree, but the operation is about text files and CRLF
|
||||
conversion is about fixing the line ending inconsistencies, so the
|
||||
safety does not trigger;
|
||||
|
||||
- "git diff" itself does not touch the files in the work tree, it is
|
||||
often run to inspect the changes you intend to next "git add". To
|
||||
catch potential problems early, safety triggers.
|
||||
|
||||
|
||||
`ident`
|
||||
^^^^^^^
|
||||
|
||||
@@ -57,6 +57,13 @@ Patterns have the following format:
|
||||
included again. If a negated pattern matches, this will
|
||||
override lower precedence patterns sources.
|
||||
|
||||
- If the pattern ends with a slash, it is removed for the
|
||||
purpose of the following description, but it would only find
|
||||
a match with a directory. In other words, `foo/` will match a
|
||||
directory `foo` and paths underneath it, but will not match a
|
||||
regular file or a symbolic link `foo` (this is consistent
|
||||
with the way how pathspec works in general in git).
|
||||
|
||||
- If the pattern does not contain a slash '/', git treats it as
|
||||
a shell glob pattern and checks for a match against the
|
||||
pathname without leading directories.
|
||||
|
||||
@@ -61,6 +61,35 @@ The default 'pre-commit' hook, when enabled, catches introduction
|
||||
of lines with trailing whitespaces and aborts the commit when
|
||||
such a line is found.
|
||||
|
||||
All the `git-commit` hooks are invoked with the environment
|
||||
variable `GIT_EDITOR=:` if the command will not bring up an editor
|
||||
to modify the commit message.
|
||||
|
||||
prepare-commit-msg
|
||||
------------------
|
||||
|
||||
This hook is invoked by `git-commit` right after preparing the
|
||||
default log message, and before the editor is started.
|
||||
|
||||
It takes one to three parameters. The first is the name of the file
|
||||
that the commit log message. The second is the source of the commit
|
||||
message, and can be: `message` (if a `\-m` or `\-F` option was
|
||||
given); `template` (if a `\-t` option was given or the
|
||||
configuration option `commit.template` is set); `merge` (if the
|
||||
commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
|
||||
(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
|
||||
a commit SHA1 (if a `\-c`, `\-C` or `\--amend` option was given).
|
||||
|
||||
If the exit status is non-zero, `git-commit` will abort.
|
||||
|
||||
The purpose of the hook is to edit the message file in place, and
|
||||
it is not suppressed by the `\--no-verify` option. A non-zero exit
|
||||
means a failure of the hook and aborts the commit. It should not
|
||||
be used as replacement for pre-commit hook.
|
||||
|
||||
The sample `prepare-commit-msg` hook that comes with git comments
|
||||
out the `Conflicts:` part of a merge's commit message.
|
||||
|
||||
commit-msg
|
||||
----------
|
||||
|
||||
|
||||
17
Documentation/manpage-1.72.xsl
Normal file
17
Documentation/manpage-1.72.xsl
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- callout.xsl: converts asciidoc callouts to man page format -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<xsl:template match="co">
|
||||
<xsl:value-of select="concat('▓fB(',substring-after(@id,'-'),')▓fR')"/>
|
||||
</xsl:template>
|
||||
<xsl:template match="calloutlist">
|
||||
<xsl:text>⌂sp </xsl:text>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:template>
|
||||
<xsl:template match="callout">
|
||||
<xsl:value-of select="concat('▓fB',substring-after(@arearefs,'-'),'. ▓fR')"/>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:text>⌂br </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
@@ -15,7 +15,8 @@ elif test -d .git &&
|
||||
VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
|
||||
case "$VN" in
|
||||
*$LF*) (exit 1) ;;
|
||||
v[0-9]*) : happy ;;
|
||||
v[0-9]*)
|
||||
git diff-index --quiet HEAD || VN="$VN-dirty" ;;
|
||||
esac
|
||||
then
|
||||
VN=$(echo "$VN" | sed -e 's/-/./g');
|
||||
@@ -25,14 +26,6 @@ fi
|
||||
|
||||
VN=$(expr "$VN" : v*'\(.*\)')
|
||||
|
||||
dirty=$(sh -c 'git diff-index --name-only HEAD' 2>/dev/null) || dirty=
|
||||
case "$dirty" in
|
||||
'')
|
||||
;;
|
||||
*)
|
||||
VN="$VN-dirty" ;;
|
||||
esac
|
||||
|
||||
if test -r $GVF
|
||||
then
|
||||
VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
|
||||
|
||||
4
INSTALL
4
INSTALL
@@ -79,8 +79,8 @@ Issues of note:
|
||||
- "perl" and POSIX-compliant shells are needed to use most of
|
||||
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.
|
||||
- "cpio" is used by git-clone when doing a local (possibly
|
||||
hardlinked) clone.
|
||||
|
||||
- Some platform specific issues are dealt with Makefile rules,
|
||||
but depending on your specific installation, you may not
|
||||
|
||||
12
Makefile
12
Makefile
@@ -137,6 +137,10 @@ all::
|
||||
# Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit
|
||||
# parallel delta searching when packing objects.
|
||||
#
|
||||
# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
|
||||
# is a simplified version of the merge sort used in glibc. This is
|
||||
# recommended if Git triggers O(n^2) behavior in your platform's qsort().
|
||||
#
|
||||
|
||||
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
@@ -231,7 +235,7 @@ SCRIPT_SH = \
|
||||
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
|
||||
git-filter-branch.sh \
|
||||
git-stash.sh \
|
||||
git-help--browse.sh
|
||||
git-web--browse.sh
|
||||
|
||||
SCRIPT_PERL = \
|
||||
git-add--interactive.perl \
|
||||
@@ -755,6 +759,10 @@ ifdef NO_MEMMEM
|
||||
COMPAT_CFLAGS += -DNO_MEMMEM
|
||||
COMPAT_OBJS += compat/memmem.o
|
||||
endif
|
||||
ifdef INTERNAL_QSORT
|
||||
COMPAT_CFLAGS += -DINTERNAL_QSORT
|
||||
COMPAT_OBJS += compat/qsort.o
|
||||
endif
|
||||
|
||||
ifdef THREADED_DELTA_SEARCH
|
||||
BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
|
||||
@@ -852,6 +860,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
|
||||
|
||||
help.o: help.c common-cmds.h GIT-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
|
||||
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
|
||||
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
|
||||
'-DGIT_INFO_PATH="$(infodir_SQ)"' $<
|
||||
|
||||
@@ -872,7 +881,6 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
-e 's|@@HTMLDIR@@|$(htmldir_SQ)|g' \
|
||||
$@.sh >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
mv $@+ $@
|
||||
|
||||
@@ -222,7 +222,7 @@ static void write_global_extended_header(const unsigned char *sha1)
|
||||
static int git_tar_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "tar.umask")) {
|
||||
if (!strcmp(value, "user")) {
|
||||
if (value && !strcmp(value, "user")) {
|
||||
tar_umask = umask(0);
|
||||
umask(tar_umask);
|
||||
} else {
|
||||
|
||||
6
attr.c
6
attr.c
@@ -406,7 +406,7 @@ static void debug_info(const char *what, struct attr_stack *elem)
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", what, elem->origin ? elem->origin : "()");
|
||||
}
|
||||
static void debug_set(const char *what, const char *match, struct git_attr *attr, void *v)
|
||||
static void debug_set(const char *what, const char *match, struct git_attr *attr, const void *v)
|
||||
{
|
||||
const char *value = v;
|
||||
|
||||
@@ -543,10 +543,10 @@ static int path_matches(const char *pathname, int pathlen,
|
||||
if (*pattern == '/')
|
||||
pattern++;
|
||||
if (pathlen < baselen ||
|
||||
(baselen && pathname[baselen - 1] != '/') ||
|
||||
(baselen && pathname[baselen] != '/') ||
|
||||
strncmp(pathname, base, baselen))
|
||||
return 0;
|
||||
return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
|
||||
return fnmatch(pattern, pathname + baselen + 1, FNM_PATHNAME) == 0;
|
||||
}
|
||||
|
||||
static int fill_one(const char *what, struct match_attr *a, int rem)
|
||||
|
||||
@@ -1430,7 +1430,7 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
|
||||
case S_IFREG:
|
||||
if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
|
||||
return error("unable to open or read %s", path);
|
||||
convert_to_git(path, buf->buf, buf->len, buf);
|
||||
convert_to_git(path, buf->buf, buf->len, buf, 0);
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
@@ -1946,7 +1946,7 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
|
||||
if (!ce)
|
||||
return 0;
|
||||
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||
if (S_ISGITLINK(ce->ce_mode)) {
|
||||
strbuf_grow(buf, 100);
|
||||
strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
|
||||
} else {
|
||||
@@ -2023,7 +2023,7 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)
|
||||
|
||||
static int verify_index_match(struct cache_entry *ce, struct stat *st)
|
||||
{
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||
if (S_ISGITLINK(ce->ce_mode)) {
|
||||
if (!S_ISDIR(st->st_mode))
|
||||
return -1;
|
||||
return 0;
|
||||
@@ -2082,12 +2082,12 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
return error("%s: does not match index",
|
||||
old_name);
|
||||
if (cached)
|
||||
st_mode = ntohl(ce->ce_mode);
|
||||
st_mode = ce->ce_mode;
|
||||
} else if (stat_ret < 0)
|
||||
return error("%s: %s", old_name, strerror(errno));
|
||||
|
||||
if (!cached)
|
||||
st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode));
|
||||
st_mode = ce_mode_from_stat(ce, st.st_mode);
|
||||
|
||||
if (patch->is_new < 0)
|
||||
patch->is_new = 0;
|
||||
@@ -2388,7 +2388,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
|
||||
ce = xcalloc(1, ce_size);
|
||||
memcpy(ce->name, path, namelen);
|
||||
ce->ce_mode = create_ce_mode(mode);
|
||||
ce->ce_flags = htons(namelen);
|
||||
ce->ce_flags = namelen;
|
||||
if (S_ISGITLINK(mode)) {
|
||||
const char *s = buf;
|
||||
|
||||
@@ -2746,6 +2746,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
static int git_apply_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "apply.whitespace")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
apply_default_whitespace = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2073,7 +2073,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
|
||||
if (strbuf_read(&buf, 0, 0) < 0)
|
||||
die("read error %s from stdin", strerror(errno));
|
||||
}
|
||||
convert_to_git(path, buf.buf, buf.len, &buf);
|
||||
convert_to_git(path, buf.buf, buf.len, &buf, 0);
|
||||
origin->file.ptr = buf.buf;
|
||||
origin->file.size = buf.len;
|
||||
pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
|
||||
@@ -2092,7 +2092,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
|
||||
if (!mode) {
|
||||
int pos = cache_name_pos(path, len);
|
||||
if (0 <= pos)
|
||||
mode = ntohl(active_cache[pos]->ce_mode);
|
||||
mode = active_cache[pos]->ce_mode;
|
||||
else
|
||||
/* Let's not bother reading from HEAD tree */
|
||||
mode = S_IFREG | 0644;
|
||||
|
||||
@@ -70,12 +70,15 @@ static int git_branch_config(const char *var, const char *value)
|
||||
}
|
||||
if (!prefixcmp(var, "color.branch.")) {
|
||||
int slot = parse_branch_color_slot(var, 13);
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
color_parse(value, var, branch_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "branch.autosetupmerge"))
|
||||
branch_track = git_config_bool(var, value);
|
||||
|
||||
if (!strcmp(var, "branch.autosetupmerge")) {
|
||||
branch_track = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
|
||||
266
builtin-commit.c
266
builtin-commit.c
@@ -160,7 +160,7 @@ static int list_paths(struct path_list *list, const char *with_tree,
|
||||
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (ce->ce_flags & htons(CE_UPDATE))
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
if (!pathspec_match(pattern, m, ce->name, 0))
|
||||
continue;
|
||||
@@ -317,6 +317,10 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
if (write_cache(fd, active_cache, active_nr) ||
|
||||
close_lock_file(&false_lock))
|
||||
die("unable to write temporary index file");
|
||||
|
||||
discard_cache();
|
||||
read_cache_from(false_lock.filename);
|
||||
|
||||
return false_lock.filename;
|
||||
}
|
||||
|
||||
@@ -343,45 +347,107 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
|
||||
return s.commitable;
|
||||
}
|
||||
|
||||
static int run_hook(const char *index_file, const char *name, ...)
|
||||
{
|
||||
struct child_process hook;
|
||||
const char *argv[10], *env[2];
|
||||
char index[PATH_MAX];
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, name);
|
||||
argv[0] = git_path("hooks/%s", name);
|
||||
i = 0;
|
||||
do {
|
||||
if (++i >= ARRAY_SIZE(argv))
|
||||
die ("run_hook(): too many arguments");
|
||||
argv[i] = va_arg(args, const char *);
|
||||
} while (argv[i]);
|
||||
va_end(args);
|
||||
|
||||
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
|
||||
env[0] = index;
|
||||
env[1] = NULL;
|
||||
|
||||
if (access(argv[0], X_OK) < 0)
|
||||
return 0;
|
||||
|
||||
memset(&hook, 0, sizeof(hook));
|
||||
hook.argv = argv;
|
||||
hook.no_stdin = 1;
|
||||
hook.stdout_to_stderr = 1;
|
||||
hook.env = env;
|
||||
|
||||
return run_command(&hook);
|
||||
}
|
||||
|
||||
static int is_a_merge(const unsigned char *sha1)
|
||||
{
|
||||
struct commit *commit = lookup_commit(sha1);
|
||||
if (!commit || parse_commit(commit))
|
||||
die("could not parse HEAD commit");
|
||||
return !!(commit->parents && commit->parents->next);
|
||||
}
|
||||
|
||||
static const char sign_off_header[] = "Signed-off-by: ";
|
||||
|
||||
static int prepare_log_message(const char *index_file, const char *prefix)
|
||||
static int prepare_to_commit(const char *index_file, const char *prefix)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int commitable, saved_color_setting;
|
||||
struct strbuf sb;
|
||||
char *buffer;
|
||||
FILE *fp;
|
||||
const char *hook_arg1 = NULL;
|
||||
const char *hook_arg2 = NULL;
|
||||
|
||||
if (!no_verify && run_hook(index_file, "pre-commit", NULL))
|
||||
return 0;
|
||||
|
||||
strbuf_init(&sb, 0);
|
||||
if (message.len) {
|
||||
strbuf_addbuf(&sb, &message);
|
||||
hook_arg1 = "message";
|
||||
} else if (logfile && !strcmp(logfile, "-")) {
|
||||
if (isatty(0))
|
||||
fprintf(stderr, "(reading log message from standard input)\n");
|
||||
if (strbuf_read(&sb, 0, 0) < 0)
|
||||
die("could not read log from standard input");
|
||||
hook_arg1 = "message";
|
||||
} else if (logfile) {
|
||||
if (strbuf_read_file(&sb, logfile, 0) < 0)
|
||||
die("could not read log file '%s': %s",
|
||||
logfile, strerror(errno));
|
||||
hook_arg1 = "message";
|
||||
} else if (use_message) {
|
||||
buffer = strstr(use_message_buffer, "\n\n");
|
||||
if (!buffer || buffer[2] == '\0')
|
||||
die("commit has empty message");
|
||||
strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
|
||||
hook_arg1 = "commit";
|
||||
hook_arg2 = use_message;
|
||||
} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
|
||||
if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
|
||||
die("could not read MERGE_MSG: %s", strerror(errno));
|
||||
hook_arg1 = "merge";
|
||||
} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
|
||||
if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
|
||||
die("could not read SQUASH_MSG: %s", strerror(errno));
|
||||
hook_arg1 = "squash";
|
||||
} else if (template_file && !stat(template_file, &statbuf)) {
|
||||
if (strbuf_read_file(&sb, template_file, 0) < 0)
|
||||
die("could not read %s: %s",
|
||||
template_file, strerror(errno));
|
||||
hook_arg1 = "template";
|
||||
}
|
||||
|
||||
/*
|
||||
* This final case does not modify the template message,
|
||||
* it just sets the argument to the prepare-commit-msg hook.
|
||||
*/
|
||||
else if (in_merge)
|
||||
hook_arg1 = "merge";
|
||||
|
||||
fp = fopen(git_path(commit_editmsg), "w");
|
||||
if (fp == NULL)
|
||||
die("could not open %s", git_path(commit_editmsg));
|
||||
@@ -413,13 +479,38 @@ static int prepare_log_message(const char *index_file, const char *prefix)
|
||||
|
||||
strbuf_release(&sb);
|
||||
|
||||
if (!use_editor) {
|
||||
if (use_editor) {
|
||||
if (in_merge)
|
||||
fprintf(fp,
|
||||
"#\n"
|
||||
"# It looks like you may be committing a MERGE.\n"
|
||||
"# If this is not correct, please remove the file\n"
|
||||
"# %s\n"
|
||||
"# and try again.\n"
|
||||
"#\n",
|
||||
git_path("MERGE_HEAD"));
|
||||
|
||||
fprintf(fp,
|
||||
"\n"
|
||||
"# Please enter the commit message for your changes.\n"
|
||||
"# (Comment lines starting with '#' will ");
|
||||
if (cleanup_mode == CLEANUP_ALL)
|
||||
fprintf(fp, "not be included)\n");
|
||||
else /* CLEANUP_SPACE, that is. */
|
||||
fprintf(fp, "be kept.\n"
|
||||
"# You can remove them yourself if you want to)\n");
|
||||
if (only_include_assumed)
|
||||
fprintf(fp, "# %s\n", only_include_assumed);
|
||||
|
||||
saved_color_setting = wt_status_use_color;
|
||||
wt_status_use_color = 0;
|
||||
commitable = run_status(fp, index_file, prefix, 1);
|
||||
wt_status_use_color = saved_color_setting;
|
||||
} else {
|
||||
struct rev_info rev;
|
||||
unsigned char sha1[20];
|
||||
const char *parent = "HEAD";
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (!active_nr && read_cache() < 0)
|
||||
die("Cannot read index");
|
||||
|
||||
@@ -427,48 +518,60 @@ static int prepare_log_message(const char *index_file, const char *prefix)
|
||||
parent = "HEAD^1";
|
||||
|
||||
if (get_sha1(parent, sha1))
|
||||
return !!active_nr;
|
||||
commitable = !!active_nr;
|
||||
else {
|
||||
init_revisions(&rev, "");
|
||||
rev.abbrev = 0;
|
||||
setup_revisions(0, NULL, &rev, parent);
|
||||
DIFF_OPT_SET(&rev.diffopt, QUIET);
|
||||
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
|
||||
run_diff_index(&rev, 1 /* cached */);
|
||||
|
||||
init_revisions(&rev, "");
|
||||
rev.abbrev = 0;
|
||||
setup_revisions(0, NULL, &rev, parent);
|
||||
DIFF_OPT_SET(&rev.diffopt, QUIET);
|
||||
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
|
||||
run_diff_index(&rev, 1 /* cached */);
|
||||
|
||||
return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
|
||||
commitable = !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_merge)
|
||||
fprintf(fp,
|
||||
"#\n"
|
||||
"# It looks like you may be committing a MERGE.\n"
|
||||
"# If this is not correct, please remove the file\n"
|
||||
"# %s\n"
|
||||
"# and try again.\n"
|
||||
"#\n",
|
||||
git_path("MERGE_HEAD"));
|
||||
|
||||
fprintf(fp,
|
||||
"\n"
|
||||
"# Please enter the commit message for your changes.\n"
|
||||
"# (Comment lines starting with '#' will ");
|
||||
if (cleanup_mode == CLEANUP_ALL)
|
||||
fprintf(fp, "not be included)\n");
|
||||
else /* CLEANUP_SPACE, that is. */
|
||||
fprintf(fp, "be kept.\n"
|
||||
"# You can remove them yourself if you want to)\n");
|
||||
if (only_include_assumed)
|
||||
fprintf(fp, "# %s\n", only_include_assumed);
|
||||
|
||||
saved_color_setting = wt_status_use_color;
|
||||
wt_status_use_color = 0;
|
||||
commitable = run_status(fp, index_file, prefix, 1);
|
||||
wt_status_use_color = saved_color_setting;
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return commitable;
|
||||
if (!commitable && !in_merge && !allow_empty &&
|
||||
!(amend && is_a_merge(head_sha1))) {
|
||||
run_status(stdout, index_file, prefix, 0);
|
||||
unlink(commit_editmsg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-read the index as pre-commit hook could have updated it,
|
||||
* and write it out as a tree. We must do this before we invoke
|
||||
* the editor and after we invoke run_status above.
|
||||
*/
|
||||
discard_cache();
|
||||
read_cache_from(index_file);
|
||||
if (!active_cache_tree)
|
||||
active_cache_tree = cache_tree();
|
||||
if (cache_tree_update(active_cache_tree,
|
||||
active_cache, active_nr, 0, 0) < 0) {
|
||||
error("Error building trees");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (run_hook(index_file, "prepare-commit-msg",
|
||||
git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
|
||||
return 0;
|
||||
|
||||
if (use_editor) {
|
||||
char index[PATH_MAX];
|
||||
const char *env[2] = { index, NULL };
|
||||
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
|
||||
launch_editor(git_path(commit_editmsg), NULL, env);
|
||||
}
|
||||
|
||||
if (!no_verify &&
|
||||
run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -565,6 +668,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
use_editor = 0;
|
||||
if (edit_flag)
|
||||
use_editor = 1;
|
||||
if (!use_editor)
|
||||
setenv("GIT_EDITOR", ":", 1);
|
||||
|
||||
if (get_sha1("HEAD", head_sha1))
|
||||
initial_commit = 1;
|
||||
@@ -601,7 +706,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
|
||||
if (get_sha1(use_message, sha1))
|
||||
die("could not lookup commit %s", use_message);
|
||||
commit = lookup_commit(sha1);
|
||||
commit = lookup_commit_reference(sha1);
|
||||
if (!commit || parse_commit(commit))
|
||||
die("could not parse commit %s", use_message);
|
||||
|
||||
@@ -677,31 +782,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
|
||||
return commitable ? 0 : 1;
|
||||
}
|
||||
|
||||
static int run_hook(const char *index_file, const char *name, const char *arg)
|
||||
{
|
||||
struct child_process hook;
|
||||
const char *argv[3], *env[2];
|
||||
char index[PATH_MAX];
|
||||
|
||||
argv[0] = git_path("hooks/%s", name);
|
||||
argv[1] = arg;
|
||||
argv[2] = NULL;
|
||||
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
|
||||
env[0] = index;
|
||||
env[1] = NULL;
|
||||
|
||||
if (access(argv[0], X_OK) < 0)
|
||||
return 0;
|
||||
|
||||
memset(&hook, 0, sizeof(hook));
|
||||
hook.argv = argv;
|
||||
hook.no_stdin = 1;
|
||||
hook.stdout_to_stderr = 1;
|
||||
hook.env = env;
|
||||
|
||||
return run_command(&hook);
|
||||
}
|
||||
|
||||
static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
{
|
||||
struct rev_info rev;
|
||||
@@ -743,6 +823,8 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
int git_commit_config(const char *k, const char *v)
|
||||
{
|
||||
if (!strcmp(k, "commit.template")) {
|
||||
if (!v)
|
||||
return config_error_nonbool(v);
|
||||
template_file = xstrdup(v);
|
||||
return 0;
|
||||
}
|
||||
@@ -750,14 +832,6 @@ int git_commit_config(const char *k, const char *v)
|
||||
return git_status_config(k, v);
|
||||
}
|
||||
|
||||
static int is_a_merge(const unsigned char *sha1)
|
||||
{
|
||||
struct commit *commit = lookup_commit(sha1);
|
||||
if (!commit || parse_commit(commit))
|
||||
die("could not parse HEAD commit");
|
||||
return !!(commit->parents && commit->parents->next);
|
||||
}
|
||||
|
||||
static const char commit_utf8_warn[] =
|
||||
"Warning: commit message does not conform to UTF-8.\n"
|
||||
"You may want to amend it after fixing the message, or set the config\n"
|
||||
@@ -789,33 +863,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
|
||||
index_file = prepare_index(argc, argv, prefix);
|
||||
|
||||
if (!no_verify && run_hook(index_file, "pre-commit", NULL)) {
|
||||
/* Set up everything for writing the commit object. This includes
|
||||
running hooks, writing the trees, and interacting with the user. */
|
||||
if (!prepare_to_commit(index_file, prefix)) {
|
||||
rollback_index_files();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!prepare_log_message(index_file, prefix) && !in_merge &&
|
||||
!allow_empty && !(amend && is_a_merge(head_sha1))) {
|
||||
run_status(stdout, index_file, prefix, 0);
|
||||
rollback_index_files();
|
||||
unlink(commit_editmsg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-read the index as pre-commit hook could have updated it,
|
||||
* and write it out as a tree.
|
||||
*/
|
||||
discard_cache();
|
||||
read_cache_from(index_file);
|
||||
if (!active_cache_tree)
|
||||
active_cache_tree = cache_tree();
|
||||
if (cache_tree_update(active_cache_tree,
|
||||
active_cache, active_nr, 0, 0) < 0) {
|
||||
rollback_index_files();
|
||||
die("Error building trees");
|
||||
}
|
||||
|
||||
/*
|
||||
* The commit object
|
||||
*/
|
||||
@@ -867,19 +921,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
|
||||
strbuf_addch(&sb, '\n');
|
||||
|
||||
/* Get the commit message and validate it */
|
||||
/* Finally, get the commit message */
|
||||
header_len = sb.len;
|
||||
if (use_editor) {
|
||||
char index[PATH_MAX];
|
||||
const char *env[2] = { index, NULL };
|
||||
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
|
||||
launch_editor(git_path(commit_editmsg), NULL, env);
|
||||
}
|
||||
if (!no_verify &&
|
||||
run_hook(index_file, "commit-msg", git_path(commit_editmsg))) {
|
||||
rollback_index_files();
|
||||
exit(1);
|
||||
}
|
||||
if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
|
||||
rollback_index_files();
|
||||
die("could not read commit message");
|
||||
@@ -929,6 +972,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
|
||||
unlink(git_path("MERGE_HEAD"));
|
||||
unlink(git_path("MERGE_MSG"));
|
||||
unlink(git_path("SQUASH_MSG"));
|
||||
|
||||
if (commit_index_files())
|
||||
die ("Repository has been updated, but unable to write\n"
|
||||
|
||||
@@ -79,9 +79,10 @@ static int get_value(const char* key_, const char* regex_)
|
||||
local = getenv(CONFIG_LOCAL_ENVIRONMENT);
|
||||
if (!local)
|
||||
local = repo_config = xstrdup(git_path("config"));
|
||||
if (home)
|
||||
if (git_config_global() && home)
|
||||
global = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
system_wide = git_etc_gitconfig();
|
||||
if (git_config_system())
|
||||
system_wide = git_etc_gitconfig();
|
||||
}
|
||||
|
||||
key = xstrdup(key_);
|
||||
@@ -168,6 +169,8 @@ static char parsed_color[COLOR_MAXLEN];
|
||||
static int git_get_color_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, get_color_slot)) {
|
||||
if (!value)
|
||||
config_error_nonbool(var);
|
||||
color_parse(value, var, parsed_color);
|
||||
get_color_found = 1;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ static int all; /* Default to annotated tags only */
|
||||
static int tags; /* But allow any tags if --tags is specified */
|
||||
static int abbrev = DEFAULT_ABBREV;
|
||||
static int max_candidates = 10;
|
||||
const char *pattern = NULL;
|
||||
|
||||
struct commit_name {
|
||||
int prio; /* annotated tag = 2, tag = 1, head = 0 */
|
||||
@@ -57,9 +58,11 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
|
||||
* Otherwise only annotated tags are used.
|
||||
*/
|
||||
if (!prefixcmp(path, "refs/tags/")) {
|
||||
if (object->type == OBJ_TAG)
|
||||
if (object->type == OBJ_TAG) {
|
||||
prio = 2;
|
||||
else
|
||||
if (pattern && fnmatch(pattern, path + 10, 0))
|
||||
prio = 0;
|
||||
} else
|
||||
prio = 1;
|
||||
}
|
||||
else
|
||||
@@ -253,7 +256,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||
OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
|
||||
OPT__ABBREV(&abbrev),
|
||||
OPT_INTEGER(0, "candidates", &max_candidates,
|
||||
"consider <n> most recent tags (default: 10)"),
|
||||
"consider <n> most recent tags (default: 10)"),
|
||||
OPT_STRING(0, "match", &pattern, "pattern",
|
||||
"only consider tags matching <pattern>"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
@@ -266,12 +271,19 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||
save_commit_buffer = 0;
|
||||
|
||||
if (contains) {
|
||||
const char **args = xmalloc((4 + argc) * sizeof(char*));
|
||||
const char **args = xmalloc((6 + argc) * sizeof(char*));
|
||||
int i = 0;
|
||||
args[i++] = "name-rev";
|
||||
args[i++] = "--name-only";
|
||||
if (!all)
|
||||
args[i++] = "--no-undefined";
|
||||
if (!all) {
|
||||
args[i++] = "--tags";
|
||||
if (pattern) {
|
||||
char *s = xmalloc(strlen("--refs=refs/tags/") + strlen(pattern) + 1);
|
||||
sprintf(s, "--refs=refs/tags/%s", pattern);
|
||||
args[i++] = s;
|
||||
}
|
||||
}
|
||||
memcpy(args + i, argv, argc * sizeof(char*));
|
||||
args[i + argc] = NULL;
|
||||
return cmd_name_rev(i + argc, args, prefix);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "pack.h"
|
||||
#include "sideband.h"
|
||||
#include "fetch-pack.h"
|
||||
#include "remote.h"
|
||||
#include "run-command.h"
|
||||
|
||||
static int transfer_unpack_limit = -1;
|
||||
@@ -548,14 +549,14 @@ static int get_pack(int xd[2], char **pack_lockfile)
|
||||
}
|
||||
|
||||
static struct ref *do_fetch_pack(int fd[2],
|
||||
const struct ref *orig_ref,
|
||||
int nr_match,
|
||||
char **match,
|
||||
char **pack_lockfile)
|
||||
{
|
||||
struct ref *ref;
|
||||
struct ref *ref = copy_ref_list(orig_ref);
|
||||
unsigned char sha1[20];
|
||||
|
||||
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
||||
if (is_repository_shallow() && !server_supports("shallow"))
|
||||
die("Server does not support shallow clients");
|
||||
if (server_supports("multi_ack")) {
|
||||
@@ -573,10 +574,6 @@ static struct ref *do_fetch_pack(int fd[2],
|
||||
fprintf(stderr, "Server supports side-band\n");
|
||||
use_sideband = 1;
|
||||
}
|
||||
if (!ref) {
|
||||
packet_flush(fd[1]);
|
||||
die("no matching remote head");
|
||||
}
|
||||
if (everything_local(&ref, nr_match, match)) {
|
||||
packet_flush(fd[1]);
|
||||
goto all_done;
|
||||
@@ -650,8 +647,10 @@ static void fetch_pack_setup(void)
|
||||
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, ret, nr_heads;
|
||||
struct ref *ref;
|
||||
struct ref *ref = NULL;
|
||||
char *dest = NULL, **heads;
|
||||
int fd[2];
|
||||
struct child_process *conn;
|
||||
|
||||
nr_heads = 0;
|
||||
heads = NULL;
|
||||
@@ -706,45 +705,20 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
|
||||
if (!dest)
|
||||
usage(fetch_pack_usage);
|
||||
|
||||
ref = fetch_pack(&args, dest, nr_heads, heads, NULL);
|
||||
ret = !ref;
|
||||
|
||||
while (ref) {
|
||||
printf("%s %s\n",
|
||||
sha1_to_hex(ref->old_sha1), ref->name);
|
||||
ref = ref->next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ref *fetch_pack(struct fetch_pack_args *my_args,
|
||||
const char *dest,
|
||||
int nr_heads,
|
||||
char **heads,
|
||||
char **pack_lockfile)
|
||||
{
|
||||
int i, ret;
|
||||
int fd[2];
|
||||
struct child_process *conn;
|
||||
struct ref *ref;
|
||||
struct stat st;
|
||||
|
||||
fetch_pack_setup();
|
||||
memcpy(&args, my_args, sizeof(args));
|
||||
if (args.depth > 0) {
|
||||
if (stat(git_path("shallow"), &st))
|
||||
st.st_mtime = 0;
|
||||
}
|
||||
|
||||
conn = git_connect(fd, (char *)dest, args.uploadpack,
|
||||
args.verbose ? CONNECT_VERBOSE : 0);
|
||||
if (heads && nr_heads)
|
||||
nr_heads = remove_duplicates(nr_heads, heads);
|
||||
ref = do_fetch_pack(fd, nr_heads, heads, pack_lockfile);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
ret = finish_connect(conn);
|
||||
args.verbose ? CONNECT_VERBOSE : 0);
|
||||
if (conn) {
|
||||
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
||||
|
||||
ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
if (finish_connect(conn))
|
||||
ref = NULL;
|
||||
} else {
|
||||
ref = NULL;
|
||||
}
|
||||
ret = !ref;
|
||||
|
||||
if (!ret && nr_heads) {
|
||||
/* If the heads to pull were given, we should have
|
||||
@@ -758,8 +732,42 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
while (ref) {
|
||||
printf("%s %s\n",
|
||||
sha1_to_hex(ref->old_sha1), ref->name);
|
||||
ref = ref->next;
|
||||
}
|
||||
|
||||
if (!ret && args.depth > 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ref *fetch_pack(struct fetch_pack_args *my_args,
|
||||
int fd[], struct child_process *conn,
|
||||
const struct ref *ref,
|
||||
const char *dest,
|
||||
int nr_heads,
|
||||
char **heads,
|
||||
char **pack_lockfile)
|
||||
{
|
||||
struct stat st;
|
||||
struct ref *ref_cpy;
|
||||
|
||||
fetch_pack_setup();
|
||||
memcpy(&args, my_args, sizeof(args));
|
||||
if (args.depth > 0) {
|
||||
if (stat(git_path("shallow"), &st))
|
||||
st.st_mtime = 0;
|
||||
}
|
||||
|
||||
if (heads && nr_heads)
|
||||
nr_heads = remove_duplicates(nr_heads, heads);
|
||||
if (!ref) {
|
||||
packet_flush(fd[1]);
|
||||
die("no matching remote head");
|
||||
}
|
||||
ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile);
|
||||
|
||||
if (args.depth > 0) {
|
||||
struct cache_time mtime;
|
||||
char *shallow = git_path("shallow");
|
||||
int fd;
|
||||
@@ -787,8 +795,5 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
ref = NULL;
|
||||
|
||||
return ref;
|
||||
return ref_cpy;
|
||||
}
|
||||
|
||||
@@ -557,6 +557,8 @@ static int do_fetch(struct transport *transport,
|
||||
|
||||
free_refs(fetch_map);
|
||||
|
||||
transport_disconnect(transport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -360,6 +360,9 @@ static int fsck_commit(struct commit *commit)
|
||||
fprintf(stderr, "Checking commit %s\n",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (!commit->date)
|
||||
return objerror(&commit->object, "invalid author/committer line");
|
||||
|
||||
if (memcmp(buffer, "tree ", 5))
|
||||
return objerror(&commit->object, "invalid format - expected 'tree' line");
|
||||
if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
|
||||
@@ -378,9 +381,6 @@ static int fsck_commit(struct commit *commit)
|
||||
return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
|
||||
if (!commit->parents && show_root)
|
||||
printf("root %s\n", sha1_to_hex(commit->object.sha1));
|
||||
if (!commit->date)
|
||||
printf("bad commit date in %s\n",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -765,7 +765,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
struct blob *blob;
|
||||
struct object *obj;
|
||||
|
||||
mode = ntohl(active_cache[i]->ce_mode);
|
||||
mode = active_cache[i]->ce_mode;
|
||||
if (S_ISGITLINK(mode))
|
||||
continue;
|
||||
blob = lookup_blob(active_cache[i]->sha1);
|
||||
|
||||
@@ -37,7 +37,7 @@ static const char *argv_rerere[] = {"rerere", "gc", NULL};
|
||||
static int gc_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "gc.packrefs")) {
|
||||
if (!strcmp(value, "notbare"))
|
||||
if (value && !strcmp(value, "notbare"))
|
||||
pack_refs = -1;
|
||||
else
|
||||
pack_refs = git_config_bool(var, value);
|
||||
|
||||
@@ -331,7 +331,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
char *name;
|
||||
int kept;
|
||||
if (!S_ISREG(ntohl(ce->ce_mode)))
|
||||
if (!S_ISREG(ce->ce_mode))
|
||||
continue;
|
||||
if (!pathspec_matches(paths, ce->name))
|
||||
continue;
|
||||
@@ -387,7 +387,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
|
||||
|
||||
for (nr = 0; nr < active_nr; nr++) {
|
||||
struct cache_entry *ce = active_cache[nr];
|
||||
if (!S_ISREG(ntohl(ce->ce_mode)))
|
||||
if (!S_ISREG(ce->ce_mode))
|
||||
continue;
|
||||
if (!pathspec_matches(paths, ce->name))
|
||||
continue;
|
||||
|
||||
@@ -141,9 +141,9 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
|
||||
*/
|
||||
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
||||
if (!is_absolute_path(template_dir)) {
|
||||
const char *exec_path = git_exec_path();
|
||||
template_dir = prefix_path(exec_path, strlen(exec_path),
|
||||
template_dir);
|
||||
struct strbuf d = STRBUF_INIT;
|
||||
strbuf_addf(&d, "%s/%s", git_exec_path(), template_dir);
|
||||
template_dir = strbuf_detach(&d, NULL);
|
||||
}
|
||||
}
|
||||
strcpy(template_path, template_dir);
|
||||
|
||||
@@ -219,7 +219,7 @@ static int git_log_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "format.subjectprefix")) {
|
||||
if (!value)
|
||||
die("format.subjectprefix without value");
|
||||
config_error_nonbool(var);
|
||||
fmt_patch_subject_prefix = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
@@ -432,7 +432,7 @@ static int git_format_config(const char *var, const char *value)
|
||||
}
|
||||
if (!strcmp(var, "format.suffix")) {
|
||||
if (!value)
|
||||
die("format.suffix without value");
|
||||
return config_error_nonbool(var);
|
||||
fmt_patch_suffix = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
@@ -440,11 +440,10 @@ static int git_format_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "format.numbered")) {
|
||||
if (!strcasecmp(value, "auto")) {
|
||||
if (value && !strcasecmp(value, "auto")) {
|
||||
auto_number = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
numbered = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
|
||||
return;
|
||||
|
||||
if (tag && *tag && show_valid_bit &&
|
||||
(ce->ce_flags & htons(CE_VALID))) {
|
||||
(ce->ce_flags & CE_VALID)) {
|
||||
static char alttag[4];
|
||||
memcpy(alttag, tag, 3);
|
||||
if (isalpha(tag[0]))
|
||||
@@ -210,7 +210,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
|
||||
} else {
|
||||
printf("%s%06o %s %d\t",
|
||||
tag,
|
||||
ntohl(ce->ce_mode),
|
||||
ce->ce_mode,
|
||||
abbrev ? find_unique_abbrev(ce->sha1,abbrev)
|
||||
: sha1_to_hex(ce->sha1),
|
||||
ce_stage(ce));
|
||||
@@ -238,11 +238,12 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
||||
if (show_cached | show_stage) {
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (excluded(dir, ce->name) != dir->show_ignored)
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
||||
continue;
|
||||
if (show_unmerged && !ce_stage(ce))
|
||||
continue;
|
||||
if (ce->ce_flags & htons(CE_UPDATE))
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
|
||||
}
|
||||
@@ -252,7 +253,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
struct stat st;
|
||||
int err;
|
||||
if (excluded(dir, ce->name) != dir->show_ignored)
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
||||
continue;
|
||||
err = lstat(ce->name, &st);
|
||||
if (show_deleted && err)
|
||||
@@ -350,7 +352,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (!ce_stage(ce))
|
||||
continue;
|
||||
ce->ce_flags |= htons(CE_STAGEMASK);
|
||||
ce->ce_flags |= CE_STAGEMASK;
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
@@ -379,7 +381,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
|
||||
*/
|
||||
if (last_stage0 &&
|
||||
!strcmp(last_stage0->name, ce->name))
|
||||
ce->ce_flags |= htons(CE_UPDATE);
|
||||
ce->ce_flags |= CE_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
||||
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
|
||||
|
||||
ref = transport_get_remote_refs(transport);
|
||||
transport_disconnect(transport);
|
||||
|
||||
if (!ref)
|
||||
return 1;
|
||||
|
||||
@@ -818,6 +818,7 @@ static void handle_body(void)
|
||||
|
||||
switch (transfer_encoding) {
|
||||
case TE_BASE64:
|
||||
case TE_QP:
|
||||
{
|
||||
char *op = line;
|
||||
|
||||
|
||||
@@ -125,18 +125,18 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
|
||||
}
|
||||
|
||||
/* returns a static buffer */
|
||||
static const char* get_rev_name(struct object *o)
|
||||
static const char *get_rev_name(struct object *o)
|
||||
{
|
||||
static char buffer[1024];
|
||||
struct rev_name *n;
|
||||
struct commit *c;
|
||||
|
||||
if (o->type != OBJ_COMMIT)
|
||||
return "undefined";
|
||||
return NULL;
|
||||
c = (struct commit *) o;
|
||||
n = c->util;
|
||||
if (!n)
|
||||
return "undefined";
|
||||
return NULL;
|
||||
|
||||
if (!n->generation)
|
||||
return n->tip_name;
|
||||
@@ -159,7 +159,7 @@ static char const * const name_rev_usage[] = {
|
||||
int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct object_array revs = { 0, 0, NULL };
|
||||
int all = 0, transform_stdin = 0;
|
||||
int all = 0, transform_stdin = 0, allow_undefined = 1;
|
||||
struct name_ref_data data = { 0, 0, NULL };
|
||||
struct option opts[] = {
|
||||
OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"),
|
||||
@@ -169,6 +169,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
OPT_GROUP(""),
|
||||
OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"),
|
||||
OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"),
|
||||
OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
@@ -226,7 +227,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
else if (++forty == 40 &&
|
||||
!ishex(*(p+1))) {
|
||||
unsigned char sha1[40];
|
||||
const char *name = "undefined";
|
||||
const char *name = NULL;
|
||||
char c = *(p+1);
|
||||
|
||||
forty = 0;
|
||||
@@ -240,11 +241,10 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
*(p+1) = c;
|
||||
|
||||
if (!strcmp(name, "undefined"))
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
fwrite(p_start, p - p_start + 1, 1,
|
||||
stdout);
|
||||
fwrite(p_start, p - p_start + 1, 1, stdout);
|
||||
printf(" (%s)", name);
|
||||
p_start = p + 1;
|
||||
}
|
||||
@@ -260,18 +260,32 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
max = get_max_object_index();
|
||||
for (i = 0; i < max; i++) {
|
||||
struct object * obj = get_indexed_object(i);
|
||||
const char *name;
|
||||
if (!obj)
|
||||
continue;
|
||||
if (!data.name_only)
|
||||
printf("%s ", sha1_to_hex(obj->sha1));
|
||||
printf("%s\n", get_rev_name(obj));
|
||||
name = get_rev_name(obj);
|
||||
if (name)
|
||||
printf("%s\n", name);
|
||||
else if (allow_undefined)
|
||||
printf("undefined\n");
|
||||
else
|
||||
die("cannot describe '%s'", sha1_to_hex(obj->sha1));
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < revs.nr; i++) {
|
||||
const char *name;
|
||||
if (!data.name_only)
|
||||
printf("%s ", revs.objects[i].name);
|
||||
printf("%s\n", get_rev_name(revs.objects[i].item));
|
||||
name = get_rev_name(revs.objects[i].item);
|
||||
if (name)
|
||||
printf("%s\n", name);
|
||||
else if (allow_undefined)
|
||||
printf("undefined\n");
|
||||
else
|
||||
die("cannot describe '%s'", sha1_to_hex(revs.objects[i].item->sha1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ static int allow_ofs_delta;
|
||||
static const char *base_name;
|
||||
static int progress = 1;
|
||||
static int window = 10;
|
||||
static uint32_t pack_size_limit;
|
||||
static uint32_t pack_size_limit, pack_size_limit_cfg;
|
||||
static int depth = 50;
|
||||
static int delta_search_threads = 1;
|
||||
static int pack_to_stdout;
|
||||
@@ -1867,6 +1867,10 @@ static int git_pack_config(const char *k, const char *v)
|
||||
die("bad pack.indexversion=%d", pack_idx_default_version);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "pack.packsizelimit")) {
|
||||
pack_size_limit_cfg = git_config_ulong(k, v);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
}
|
||||
|
||||
@@ -2096,6 +2100,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!prefixcmp(arg, "--max-pack-size=")) {
|
||||
char *end;
|
||||
pack_size_limit_cfg = 0;
|
||||
pack_size_limit = strtoul(arg+16, &end, 0) * 1024 * 1024;
|
||||
if (!arg[16] || *end)
|
||||
usage(pack_usage);
|
||||
@@ -2220,6 +2225,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
if (pack_to_stdout != !base_name)
|
||||
usage(pack_usage);
|
||||
|
||||
if (!pack_to_stdout && !pack_size_limit)
|
||||
pack_size_limit = pack_size_limit_cfg;
|
||||
|
||||
if (pack_to_stdout && pack_size_limit)
|
||||
die("--max-pack-size cannot be used to build a pack for transfer.");
|
||||
|
||||
|
||||
@@ -83,6 +83,44 @@ static void prune_object_dir(const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write errors (particularly out of space) can result in
|
||||
* failed temporary packs (and more rarely indexes and other
|
||||
* files begining with "tmp_") accumulating in the
|
||||
* object directory.
|
||||
*/
|
||||
static void remove_temporary_files(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
char* dirname=get_object_directory();
|
||||
|
||||
dir = opendir(dirname);
|
||||
if (!dir) {
|
||||
fprintf(stderr, "Unable to open object directory %s\n",
|
||||
dirname);
|
||||
return;
|
||||
}
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (!prefixcmp(de->d_name, "tmp_")) {
|
||||
char name[PATH_MAX];
|
||||
int c = snprintf(name, PATH_MAX, "%s/%s",
|
||||
dirname, de->d_name);
|
||||
if (c < 0 || c >= PATH_MAX)
|
||||
continue;
|
||||
if (expire) {
|
||||
struct stat st;
|
||||
if (stat(name, &st) != 0 || st.st_mtime >= expire)
|
||||
continue;
|
||||
}
|
||||
printf("Removing stale temporary file %s\n", name);
|
||||
if (!show_only)
|
||||
unlink(name);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@@ -115,5 +153,6 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
|
||||
sync();
|
||||
prune_packed_objects(show_only);
|
||||
remove_temporary_files();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ static int read_cache_unmerged(void)
|
||||
continue;
|
||||
cache_tree_invalidate_path(active_cache_tree, ce->name);
|
||||
last = ce;
|
||||
ce->ce_mode = 0;
|
||||
ce->ce_flags &= ~htons(CE_STAGEMASK);
|
||||
ce->ce_flags |= CE_REMOVE;
|
||||
}
|
||||
*dst++ = ce;
|
||||
}
|
||||
|
||||
@@ -307,13 +307,19 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused
|
||||
|
||||
static int reflog_expire_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "gc.reflogexpire"))
|
||||
if (!strcmp(var, "gc.reflogexpire")) {
|
||||
if (!value)
|
||||
config_error_nonbool(var);
|
||||
default_reflog_expire = approxidate(value);
|
||||
else if (!strcmp(var, "gc.reflogexpireunreachable"))
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "gc.reflogexpireunreachable")) {
|
||||
if (!value)
|
||||
config_error_nonbool(var);
|
||||
default_reflog_expire_unreachable = approxidate(value);
|
||||
else
|
||||
return git_default_config(var, value);
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
||||
|
||||
@@ -149,8 +149,8 @@ static int find_conflict(struct path_list *conflict)
|
||||
if (ce_stage(e2) == 2 &&
|
||||
ce_stage(e3) == 3 &&
|
||||
ce_same_name(e2, e3) &&
|
||||
S_ISREG(ntohl(e2->ce_mode)) &&
|
||||
S_ISREG(ntohl(e3->ce_mode))) {
|
||||
S_ISREG(e2->ce_mode) &&
|
||||
S_ISREG(e3->ce_mode)) {
|
||||
path_list_insert((const char *)e2->name, conflict);
|
||||
i++; /* skip over both #2 and #3 */
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "exec_cmd.h"
|
||||
#include "utf8.h"
|
||||
#include "parse-options.h"
|
||||
#include "cache-tree.h"
|
||||
|
||||
/*
|
||||
* This implements the builtins revert and cherry-pick.
|
||||
@@ -270,7 +271,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
* that represents the "current" state for merge-recursive
|
||||
* to work on.
|
||||
*/
|
||||
if (write_tree(head, 0, NULL))
|
||||
if (write_cache_as_tree(head, 0, NULL))
|
||||
die ("Your index file is unmerged.");
|
||||
} else {
|
||||
struct wt_status s;
|
||||
@@ -357,7 +358,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
if (merge_recursive(sha1_to_hex(base->object.sha1),
|
||||
sha1_to_hex(head), "HEAD",
|
||||
sha1_to_hex(next->object.sha1), oneline) ||
|
||||
write_tree(head, 0, NULL)) {
|
||||
write_cache_as_tree(head, 0, NULL)) {
|
||||
add_to_msg("\nConflicts:\n\n");
|
||||
read_cache();
|
||||
for (i = 0; i < active_nr;) {
|
||||
|
||||
@@ -536,6 +536,8 @@ static void append_one_rev(const char *av)
|
||||
static int git_show_branch_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "showbranch.default")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
if (default_alloc <= default_num + 1) {
|
||||
default_alloc = default_alloc * 3 / 2 + 20;
|
||||
default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
|
||||
|
||||
@@ -258,7 +258,7 @@ static int git_tag_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "user.signingkey")) {
|
||||
if (!value)
|
||||
die("user.signingkey without value");
|
||||
return config_error_nonbool(value);
|
||||
set_signingkey(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ static int mark_valid(const char *path)
|
||||
if (0 <= pos) {
|
||||
switch (mark_valid_only) {
|
||||
case MARK_VALID:
|
||||
active_cache[pos]->ce_flags |= htons(CE_VALID);
|
||||
active_cache[pos]->ce_flags |= CE_VALID;
|
||||
break;
|
||||
case UNMARK_VALID:
|
||||
active_cache[pos]->ce_flags &= ~htons(CE_VALID);
|
||||
active_cache[pos]->ce_flags &= ~CE_VALID;
|
||||
break;
|
||||
}
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
@@ -95,7 +95,7 @@ static int add_one_path(struct cache_entry *old, const char *path, int len, stru
|
||||
size = cache_entry_size(len);
|
||||
ce = xcalloc(1, size);
|
||||
memcpy(ce->name, path, len);
|
||||
ce->ce_flags = htons(len);
|
||||
ce->ce_flags = len;
|
||||
fill_stat_cache_info(ce, st);
|
||||
ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
|
||||
|
||||
@@ -139,7 +139,7 @@ static int process_directory(const char *path, int len, struct stat *st)
|
||||
/* Exact match: file or existing gitlink */
|
||||
if (pos >= 0) {
|
||||
struct cache_entry *ce = active_cache[pos];
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||
if (S_ISGITLINK(ce->ce_mode)) {
|
||||
|
||||
/* Do nothing to the index if there is no HEAD! */
|
||||
if (resolve_gitlink_ref(path, "HEAD", sha1) < 0)
|
||||
@@ -183,7 +183,7 @@ static int process_file(const char *path, int len, struct stat *st)
|
||||
int pos = cache_name_pos(path, len);
|
||||
struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];
|
||||
|
||||
if (ce && S_ISGITLINK(ntohl(ce->ce_mode)))
|
||||
if (ce && S_ISGITLINK(ce->ce_mode))
|
||||
return error("%s is already a gitlink, not replacing", path);
|
||||
|
||||
return add_one_path(ce, path, len, st);
|
||||
@@ -226,7 +226,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
|
||||
ce->ce_flags = create_ce_flags(len, stage);
|
||||
ce->ce_mode = create_ce_mode(mode);
|
||||
if (assume_unchanged)
|
||||
ce->ce_flags |= htons(CE_VALID);
|
||||
ce->ce_flags |= CE_VALID;
|
||||
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
|
||||
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
|
||||
if (add_cache_entry(ce, option))
|
||||
@@ -246,14 +246,14 @@ static void chmod_path(int flip, const char *path)
|
||||
if (pos < 0)
|
||||
goto fail;
|
||||
ce = active_cache[pos];
|
||||
mode = ntohl(ce->ce_mode);
|
||||
mode = ce->ce_mode;
|
||||
if (!S_ISREG(mode))
|
||||
goto fail;
|
||||
switch (flip) {
|
||||
case '+':
|
||||
ce->ce_mode |= htonl(0111); break;
|
||||
ce->ce_mode |= 0111; break;
|
||||
case '-':
|
||||
ce->ce_mode &= htonl(~0111); break;
|
||||
ce->ce_mode &= ~0111; break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -11,63 +11,12 @@
|
||||
static const char write_tree_usage[] =
|
||||
"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
|
||||
|
||||
int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
|
||||
{
|
||||
int entries, was_valid, newfd;
|
||||
|
||||
/* We can't free this memory, it becomes part of a linked list parsed atexit() */
|
||||
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
newfd = hold_locked_index(lock_file, 1);
|
||||
|
||||
entries = read_cache();
|
||||
if (entries < 0)
|
||||
die("git-write-tree: error reading cache");
|
||||
|
||||
if (!active_cache_tree)
|
||||
active_cache_tree = cache_tree();
|
||||
|
||||
was_valid = cache_tree_fully_valid(active_cache_tree);
|
||||
|
||||
if (!was_valid) {
|
||||
if (cache_tree_update(active_cache_tree,
|
||||
active_cache, active_nr,
|
||||
missing_ok, 0) < 0)
|
||||
die("git-write-tree: error building trees");
|
||||
if (0 <= newfd) {
|
||||
if (!write_cache(newfd, active_cache, active_nr) &&
|
||||
!commit_lock_file(lock_file))
|
||||
newfd = -1;
|
||||
}
|
||||
/* Not being able to write is fine -- we are only interested
|
||||
* in updating the cache-tree part, and if the next caller
|
||||
* ends up using the old index with unupdated cache-tree part
|
||||
* it misses the work we did here, but that is just a
|
||||
* performance penalty and not a big deal.
|
||||
*/
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
struct cache_tree *subtree =
|
||||
cache_tree_find(active_cache_tree, prefix);
|
||||
if (!subtree)
|
||||
die("git-write-tree: prefix %s not found", prefix);
|
||||
hashcpy(sha1, subtree->sha1);
|
||||
}
|
||||
else
|
||||
hashcpy(sha1, active_cache_tree->sha1);
|
||||
|
||||
if (0 <= newfd)
|
||||
rollback_lock_file(lock_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
{
|
||||
int missing_ok = 0, ret;
|
||||
const char *prefix = NULL;
|
||||
unsigned char sha1[20];
|
||||
const char *me = "git-write-tree";
|
||||
|
||||
git_config(git_default_config);
|
||||
while (1 < argc) {
|
||||
@@ -84,8 +33,20 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
if (argc > 2)
|
||||
die("too many options");
|
||||
|
||||
ret = write_tree(sha1, missing_ok, prefix);
|
||||
printf("%s\n", sha1_to_hex(sha1));
|
||||
|
||||
ret = write_cache_as_tree(sha1, missing_ok, prefix);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
printf("%s\n", sha1_to_hex(sha1));
|
||||
break;
|
||||
case WRITE_TREE_UNREADABLE_INDEX:
|
||||
die("%s: error reading the index", me);
|
||||
break;
|
||||
case WRITE_TREE_UNMERGED_INDEX:
|
||||
die("%s: error building trees; the index is unmerged?", me);
|
||||
break;
|
||||
case WRITE_TREE_PREFIX_ERROR:
|
||||
die("%s: prefix %s not found", me, prefix);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ extern const char git_usage_string[];
|
||||
|
||||
extern void list_common_cmds_help(void);
|
||||
extern void help_unknown_cmd(const char *cmd);
|
||||
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
||||
extern void prune_packed_objects(int);
|
||||
|
||||
extern int cmd_add(int argc, const char **argv, const char *prefix);
|
||||
|
||||
59
cache-tree.c
59
cache-tree.c
@@ -320,13 +320,13 @@ static int update_one(struct cache_tree *it,
|
||||
}
|
||||
else {
|
||||
sha1 = ce->sha1;
|
||||
mode = ntohl(ce->ce_mode);
|
||||
mode = ce->ce_mode;
|
||||
entlen = pathlen - baselen;
|
||||
}
|
||||
if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))
|
||||
return error("invalid object %s", sha1_to_hex(sha1));
|
||||
|
||||
if (!ce->ce_mode)
|
||||
if (ce->ce_flags & CE_REMOVE)
|
||||
continue; /* entry being removed */
|
||||
|
||||
strbuf_grow(&buffer, entlen + 100);
|
||||
@@ -529,3 +529,58 @@ struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix)
|
||||
{
|
||||
int entries, was_valid, newfd;
|
||||
|
||||
/*
|
||||
* We can't free this memory, it becomes part of a linked list
|
||||
* parsed atexit()
|
||||
*/
|
||||
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
newfd = hold_locked_index(lock_file, 1);
|
||||
|
||||
entries = read_cache();
|
||||
if (entries < 0)
|
||||
return WRITE_TREE_UNREADABLE_INDEX;
|
||||
|
||||
if (!active_cache_tree)
|
||||
active_cache_tree = cache_tree();
|
||||
|
||||
was_valid = cache_tree_fully_valid(active_cache_tree);
|
||||
|
||||
if (!was_valid) {
|
||||
if (cache_tree_update(active_cache_tree,
|
||||
active_cache, active_nr,
|
||||
missing_ok, 0) < 0)
|
||||
return WRITE_TREE_UNMERGED_INDEX;
|
||||
if (0 <= newfd) {
|
||||
if (!write_cache(newfd, active_cache, active_nr) &&
|
||||
!commit_lock_file(lock_file))
|
||||
newfd = -1;
|
||||
}
|
||||
/* Not being able to write is fine -- we are only interested
|
||||
* in updating the cache-tree part, and if the next caller
|
||||
* ends up using the old index with unupdated cache-tree part
|
||||
* it misses the work we did here, but that is just a
|
||||
* performance penalty and not a big deal.
|
||||
*/
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
struct cache_tree *subtree =
|
||||
cache_tree_find(active_cache_tree, prefix);
|
||||
if (!subtree)
|
||||
return WRITE_TREE_PREFIX_ERROR;
|
||||
hashcpy(sha1, subtree->sha1);
|
||||
}
|
||||
else
|
||||
hashcpy(sha1, active_cache_tree->sha1);
|
||||
|
||||
if (0 <= newfd)
|
||||
rollback_lock_file(lock_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,4 +30,9 @@ int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int)
|
||||
|
||||
struct cache_tree *cache_tree_find(struct cache_tree *, const char *);
|
||||
|
||||
#define WRITE_TREE_UNREADABLE_INDEX (-1)
|
||||
#define WRITE_TREE_UNMERGED_INDEX (-2)
|
||||
#define WRITE_TREE_PREFIX_ERROR (-3)
|
||||
|
||||
int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
||||
#endif
|
||||
|
||||
103
cache.h
103
cache.h
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "git-compat-util.h"
|
||||
#include "strbuf.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include SHA1_HEADER
|
||||
#include <zlib.h>
|
||||
@@ -94,66 +95,116 @@ struct cache_time {
|
||||
* We save the fields in big-endian order to allow using the
|
||||
* index file over NFS transparently.
|
||||
*/
|
||||
struct ondisk_cache_entry {
|
||||
struct cache_time ctime;
|
||||
struct cache_time mtime;
|
||||
unsigned int dev;
|
||||
unsigned int ino;
|
||||
unsigned int mode;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int size;
|
||||
unsigned char sha1[20];
|
||||
unsigned short flags;
|
||||
char name[FLEX_ARRAY]; /* more */
|
||||
};
|
||||
|
||||
struct cache_entry {
|
||||
struct cache_time ce_ctime;
|
||||
struct cache_time ce_mtime;
|
||||
struct cache_entry *next;
|
||||
unsigned int ce_ctime;
|
||||
unsigned int ce_mtime;
|
||||
unsigned int ce_dev;
|
||||
unsigned int ce_ino;
|
||||
unsigned int ce_mode;
|
||||
unsigned int ce_uid;
|
||||
unsigned int ce_gid;
|
||||
unsigned int ce_size;
|
||||
unsigned int ce_flags;
|
||||
unsigned char sha1[20];
|
||||
unsigned short ce_flags;
|
||||
char name[FLEX_ARRAY]; /* more */
|
||||
};
|
||||
|
||||
#define CE_NAMEMASK (0x0fff)
|
||||
#define CE_STAGEMASK (0x3000)
|
||||
#define CE_UPDATE (0x4000)
|
||||
#define CE_VALID (0x8000)
|
||||
#define CE_STAGESHIFT 12
|
||||
|
||||
#define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
|
||||
#define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags))
|
||||
/* In-memory only */
|
||||
#define CE_UPDATE (0x10000)
|
||||
#define CE_REMOVE (0x20000)
|
||||
#define CE_UPTODATE (0x40000)
|
||||
#define CE_UNHASHED (0x80000)
|
||||
|
||||
static inline unsigned create_ce_flags(size_t len, unsigned stage)
|
||||
{
|
||||
if (len >= CE_NAMEMASK)
|
||||
len = CE_NAMEMASK;
|
||||
return (len | (stage << CE_STAGESHIFT));
|
||||
}
|
||||
|
||||
static inline size_t ce_namelen(const struct cache_entry *ce)
|
||||
{
|
||||
size_t len = ce->ce_flags & CE_NAMEMASK;
|
||||
if (len < CE_NAMEMASK)
|
||||
return len;
|
||||
return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
|
||||
}
|
||||
|
||||
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
|
||||
#define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT)
|
||||
#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
|
||||
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
|
||||
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
|
||||
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
|
||||
|
||||
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
|
||||
static inline unsigned int create_ce_mode(unsigned int mode)
|
||||
{
|
||||
if (S_ISLNK(mode))
|
||||
return htonl(S_IFLNK);
|
||||
return S_IFLNK;
|
||||
if (S_ISDIR(mode) || S_ISGITLINK(mode))
|
||||
return htonl(S_IFGITLINK);
|
||||
return htonl(S_IFREG | ce_permissions(mode));
|
||||
return S_IFGITLINK;
|
||||
return S_IFREG | ce_permissions(mode);
|
||||
}
|
||||
static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
|
||||
{
|
||||
extern int trust_executable_bit, has_symlinks;
|
||||
if (!has_symlinks && S_ISREG(mode) &&
|
||||
ce && S_ISLNK(ntohl(ce->ce_mode)))
|
||||
ce && S_ISLNK(ce->ce_mode))
|
||||
return ce->ce_mode;
|
||||
if (!trust_executable_bit && S_ISREG(mode)) {
|
||||
if (ce && S_ISREG(ntohl(ce->ce_mode)))
|
||||
if (ce && S_ISREG(ce->ce_mode))
|
||||
return ce->ce_mode;
|
||||
return create_ce_mode(0666);
|
||||
}
|
||||
return create_ce_mode(mode);
|
||||
}
|
||||
static inline int ce_to_dtype(const struct cache_entry *ce)
|
||||
{
|
||||
unsigned ce_mode = ntohl(ce->ce_mode);
|
||||
if (S_ISREG(ce_mode))
|
||||
return DT_REG;
|
||||
else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
|
||||
return DT_DIR;
|
||||
else if (S_ISLNK(ce_mode))
|
||||
return DT_LNK;
|
||||
else
|
||||
return DT_UNKNOWN;
|
||||
}
|
||||
#define canon_mode(mode) \
|
||||
(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
|
||||
S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
|
||||
|
||||
#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
|
||||
#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7)
|
||||
|
||||
struct index_state {
|
||||
struct cache_entry **cache;
|
||||
unsigned int cache_nr, cache_alloc, cache_changed;
|
||||
struct cache_tree *cache_tree;
|
||||
time_t timestamp;
|
||||
void *mmap;
|
||||
size_t mmap_size;
|
||||
void *alloc;
|
||||
unsigned name_hash_initialized : 1;
|
||||
struct hash_table name_hash;
|
||||
};
|
||||
|
||||
extern struct index_state the_index;
|
||||
@@ -177,6 +228,7 @@ extern struct index_state the_index;
|
||||
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
|
||||
#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
|
||||
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
|
||||
#define cache_name_exists(name, namelen) index_name_exists(&the_index, (name), (namelen))
|
||||
#endif
|
||||
|
||||
enum object_type {
|
||||
@@ -263,6 +315,7 @@ extern int read_index_from(struct index_state *, const char *path);
|
||||
extern int write_index(struct index_state *, int newfd);
|
||||
extern int discard_index(struct index_state *);
|
||||
extern int verify_path(const char *path);
|
||||
extern int index_name_exists(struct index_state *istate, const char *name, int namelen);
|
||||
extern int index_name_pos(struct index_state *, const char *name, int namelen);
|
||||
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
|
||||
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
|
||||
@@ -330,6 +383,14 @@ extern size_t packed_git_limit;
|
||||
extern size_t delta_base_cache_limit;
|
||||
extern int auto_crlf;
|
||||
|
||||
enum safe_crlf {
|
||||
SAFE_CRLF_FALSE = 0,
|
||||
SAFE_CRLF_FAIL = 1,
|
||||
SAFE_CRLF_WARN = 2,
|
||||
};
|
||||
|
||||
extern enum safe_crlf safe_crlf;
|
||||
|
||||
#define GIT_REPO_VERSION 0
|
||||
extern int repository_format_version;
|
||||
extern int check_repository_format(void);
|
||||
@@ -588,11 +649,16 @@ extern int git_parse_ulong(const char *, unsigned long *);
|
||||
extern int git_config_int(const char *, const char *);
|
||||
extern unsigned long git_config_ulong(const char *, const char *);
|
||||
extern int git_config_bool(const char *, const char *);
|
||||
extern int git_config_string(const char **, const char *, const char *);
|
||||
extern int git_config_set(const char *, const char *);
|
||||
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
||||
extern int git_config_rename_section(const char *, const char *);
|
||||
extern const char *git_etc_gitconfig(void);
|
||||
extern int check_repository_format_version(const char *var, const char *value);
|
||||
extern int git_env_bool(const char *, int);
|
||||
extern int git_config_system(void);
|
||||
extern int git_config_global(void);
|
||||
extern int config_error_nonbool(const char *);
|
||||
|
||||
#define MAX_GITNAME (1000)
|
||||
extern char git_default_email[MAX_GITNAME];
|
||||
@@ -612,12 +678,12 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
|
||||
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
extern char *pager_program;
|
||||
extern const char *pager_program;
|
||||
extern int pager_in_use(void);
|
||||
extern int pager_use_color;
|
||||
|
||||
extern char *editor_program;
|
||||
extern char *excludes_file;
|
||||
extern const char *editor_program;
|
||||
extern const char *excludes_file;
|
||||
|
||||
/* base85 */
|
||||
int decode_85(char *dst, const char *line, int linelen);
|
||||
@@ -637,7 +703,8 @@ extern void trace_argv_printf(const char **argv, const char *format, ...);
|
||||
|
||||
/* convert.c */
|
||||
/* returns 1 if *dst was used */
|
||||
extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
|
||||
extern int convert_to_git(const char *path, const char *src, size_t len,
|
||||
struct strbuf *dst, enum safe_crlf checksafe);
|
||||
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
|
||||
|
||||
/* add */
|
||||
|
||||
2
color.c
2
color.c
@@ -17,7 +17,7 @@ static int parse_color(const char *name, int len)
|
||||
return i - 1;
|
||||
}
|
||||
i = strtol(name, &end, 10);
|
||||
if (*name && !*end && i >= -1 && i <= 255)
|
||||
if (end - name == len && i >= -1 && i <= 255)
|
||||
return i;
|
||||
return -2;
|
||||
}
|
||||
|
||||
62
compat/qsort.c
Normal file
62
compat/qsort.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
/*
|
||||
* A merge sort implementation, simplified from the qsort implementation
|
||||
* by Mike Haertel, which is a part of the GNU C Library.
|
||||
*/
|
||||
|
||||
static void msort_with_tmp(void *b, size_t n, size_t s,
|
||||
int (*cmp)(const void *, const void *),
|
||||
char *t)
|
||||
{
|
||||
char *tmp;
|
||||
char *b1, *b2;
|
||||
size_t n1, n2;
|
||||
|
||||
if (n <= 1)
|
||||
return;
|
||||
|
||||
n1 = n / 2;
|
||||
n2 = n - n1;
|
||||
b1 = b;
|
||||
b2 = (char *)b + (n1 * s);
|
||||
|
||||
msort_with_tmp(b1, n1, s, cmp, t);
|
||||
msort_with_tmp(b2, n2, s, cmp, t);
|
||||
|
||||
tmp = t;
|
||||
|
||||
while (n1 > 0 && n2 > 0) {
|
||||
if (cmp(b1, b2) <= 0) {
|
||||
memcpy(tmp, b1, s);
|
||||
tmp += s;
|
||||
b1 += s;
|
||||
--n1;
|
||||
} else {
|
||||
memcpy(tmp, b2, s);
|
||||
tmp += s;
|
||||
b2 += s;
|
||||
--n2;
|
||||
}
|
||||
}
|
||||
if (n1 > 0)
|
||||
memcpy(tmp, b1, n1 * s);
|
||||
memcpy(b, t, (n - n2) * s);
|
||||
}
|
||||
|
||||
void git_qsort(void *b, size_t n, size_t s,
|
||||
int (*cmp)(const void *, const void *))
|
||||
{
|
||||
const size_t size = n * s;
|
||||
char buf[1024];
|
||||
|
||||
if (size < sizeof(buf)) {
|
||||
/* The temporary array fits on the small on-stack buffer. */
|
||||
msort_with_tmp(b, n, s, cmp, buf);
|
||||
} else {
|
||||
/* It's somewhat large, so malloc it. */
|
||||
char *tmp = malloc(size);
|
||||
msort_with_tmp(b, n, s, cmp, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
96
config.c
96
config.c
@@ -309,6 +309,14 @@ int git_config_bool(const char *name, const char *value)
|
||||
return git_config_int(name, value) != 0;
|
||||
}
|
||||
|
||||
int git_config_string(const char **dest, const char *var, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
*dest = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_default_config(const char *var, const char *value)
|
||||
{
|
||||
/* This needs a better name */
|
||||
@@ -407,50 +415,52 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.safecrlf")) {
|
||||
if (value && !strcasecmp(value, "warn")) {
|
||||
safe_crlf = SAFE_CRLF_WARN;
|
||||
return 0;
|
||||
}
|
||||
safe_crlf = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "user.name")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strlcpy(git_default_name, value, sizeof(git_default_name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "user.email")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strlcpy(git_default_email, value, sizeof(git_default_email));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "i18n.commitencoding")) {
|
||||
git_commit_encoding = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "i18n.logoutputencoding")) {
|
||||
git_log_output_encoding = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "i18n.commitencoding"))
|
||||
return git_config_string(&git_commit_encoding, var, value);
|
||||
|
||||
if (!strcmp(var, "i18n.logoutputencoding"))
|
||||
return git_config_string(&git_log_output_encoding, var, value);
|
||||
|
||||
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
|
||||
pager_use_color = git_config_bool(var,value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.pager")) {
|
||||
pager_program = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "core.pager"))
|
||||
return git_config_string(&pager_program, var, value);
|
||||
|
||||
if (!strcmp(var, "core.editor")) {
|
||||
editor_program = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "core.editor"))
|
||||
return git_config_string(&editor_program, var, value);
|
||||
|
||||
if (!strcmp(var, "core.excludesfile")) {
|
||||
if (!value)
|
||||
die("core.excludesfile without value");
|
||||
excludes_file = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "core.excludesfile"))
|
||||
return git_config_string(&excludes_file, var, value);
|
||||
|
||||
if (!strcmp(var, "core.whitespace")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
whitespace_rule_cfg = parse_whitespace_rule(value);
|
||||
return 0;
|
||||
}
|
||||
@@ -484,14 +494,30 @@ const char *git_etc_gitconfig(void)
|
||||
system_wide = ETC_GITCONFIG;
|
||||
if (!is_absolute_path(system_wide)) {
|
||||
/* interpret path relative to exec-dir */
|
||||
const char *exec_path = git_exec_path();
|
||||
system_wide = prefix_path(exec_path, strlen(exec_path),
|
||||
system_wide);
|
||||
struct strbuf d = STRBUF_INIT;
|
||||
strbuf_addf(&d, "%s/%s", git_exec_path(), system_wide);
|
||||
system_wide = strbuf_detach(&d, NULL);
|
||||
}
|
||||
}
|
||||
return system_wide;
|
||||
}
|
||||
|
||||
int git_env_bool(const char *k, int def)
|
||||
{
|
||||
const char *v = getenv(k);
|
||||
return v ? git_config_bool(k, v) : def;
|
||||
}
|
||||
|
||||
int git_config_system(void)
|
||||
{
|
||||
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
|
||||
}
|
||||
|
||||
int git_config_global(void)
|
||||
{
|
||||
return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
|
||||
}
|
||||
|
||||
int git_config(config_fn_t fn)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -504,7 +530,7 @@ int git_config(config_fn_t fn)
|
||||
* config file otherwise. */
|
||||
filename = getenv(CONFIG_ENVIRONMENT);
|
||||
if (!filename) {
|
||||
if (!access(git_etc_gitconfig(), R_OK))
|
||||
if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
|
||||
ret += git_config_from_file(fn, git_etc_gitconfig());
|
||||
home = getenv("HOME");
|
||||
filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
|
||||
@@ -512,7 +538,7 @@ int git_config(config_fn_t fn)
|
||||
filename = repo_config = xstrdup(git_path("config"));
|
||||
}
|
||||
|
||||
if (home) {
|
||||
if (git_config_global() && home) {
|
||||
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
if (!access(user_config, R_OK))
|
||||
ret = git_config_from_file(fn, user_config);
|
||||
@@ -701,12 +727,17 @@ static ssize_t find_beginning_of_line(const char* contents, size_t size,
|
||||
size_t equal_offset = size, bracket_offset = size;
|
||||
ssize_t offset;
|
||||
|
||||
contline:
|
||||
for (offset = offset_-2; offset > 0
|
||||
&& contents[offset] != '\n'; offset--)
|
||||
switch (contents[offset]) {
|
||||
case '=': equal_offset = offset; break;
|
||||
case ']': bracket_offset = offset; break;
|
||||
}
|
||||
if (offset > 0 && contents[offset-1] == '\\') {
|
||||
offset_ = offset;
|
||||
goto contline;
|
||||
}
|
||||
if (bracket_offset < equal_offset) {
|
||||
*found_bracket = 1;
|
||||
offset = bracket_offset+1;
|
||||
@@ -1074,3 +1105,12 @@ int git_config_rename_section(const char *old_name, const char *new_name)
|
||||
free(config_filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this to report error for your variable that should not
|
||||
* get a boolean value (i.e. "[my] var" means "true").
|
||||
*/
|
||||
int config_error_nonbool(const char *var)
|
||||
{
|
||||
return error("Missing value for '%s'", var);
|
||||
}
|
||||
|
||||
22
connect.c
22
connect.c
@@ -370,6 +370,8 @@ static int git_proxy_command_options(const char *var, const char *value)
|
||||
|
||||
if (git_proxy_command)
|
||||
return 0;
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
/* [core]
|
||||
* ;# matches www.kernel.org as well
|
||||
* gitproxy = netcatter-1 for kernel.org
|
||||
@@ -472,14 +474,18 @@ char *get_port(char *host)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct child_process no_fork;
|
||||
|
||||
/*
|
||||
* This returns NULL if the transport protocol does not need fork(2), or a
|
||||
* struct child_process object if it does. Once done, finish the connection
|
||||
* with finish_connect() with the value returned from this function
|
||||
* (it is safe to call finish_connect() with NULL to support the former
|
||||
* case).
|
||||
* This returns a dummy child_process if the transport protocol does not
|
||||
* need fork(2), or a struct child_process object if it does. Once done,
|
||||
* finish the connection with finish_connect() with the value returned from
|
||||
* this function (it is safe to call finish_connect() with NULL to support
|
||||
* the former case).
|
||||
*
|
||||
* If it returns, the connect is successful; it just dies on errors.
|
||||
* If it returns, the connect is successful; it just dies on errors (this
|
||||
* will hopefully be changed in a libification effort, to return NULL when
|
||||
* the connection failed).
|
||||
*/
|
||||
struct child_process *git_connect(int fd[2], const char *url_orig,
|
||||
const char *prog, int flags)
|
||||
@@ -583,7 +589,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
||||
free(url);
|
||||
if (free_path)
|
||||
free(path);
|
||||
return NULL;
|
||||
return &no_fork;
|
||||
}
|
||||
|
||||
conn = xcalloc(1, sizeof(*conn));
|
||||
@@ -641,7 +647,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
||||
int finish_connect(struct child_process *conn)
|
||||
{
|
||||
int code;
|
||||
if (!conn)
|
||||
if (!conn || conn == &no_fork)
|
||||
return 0;
|
||||
|
||||
code = finish_command(conn);
|
||||
|
||||
@@ -64,12 +64,41 @@ __gitdir ()
|
||||
|
||||
__git_ps1 ()
|
||||
{
|
||||
local b="$(git symbolic-ref HEAD 2>/dev/null)"
|
||||
if [ -n "$b" ]; then
|
||||
if [ -n "$1" ]; then
|
||||
printf "$1" "${b##refs/heads/}"
|
||||
local g="$(git rev-parse --git-dir 2>/dev/null)"
|
||||
if [ -n "$g" ]; then
|
||||
local r
|
||||
local b
|
||||
if [ -d "$g/../.dotest" ]
|
||||
then
|
||||
r="|AM/REBASE"
|
||||
b="$(git symbolic-ref HEAD 2>/dev/null)"
|
||||
elif [ -f "$g/.dotest-merge/interactive" ]
|
||||
then
|
||||
r="|REBASE-i"
|
||||
b="$(cat $g/.dotest-merge/head-name)"
|
||||
elif [ -d "$g/.dotest-merge" ]
|
||||
then
|
||||
r="|REBASE-m"
|
||||
b="$(cat $g/.dotest-merge/head-name)"
|
||||
elif [ -f "$g/MERGE_HEAD" ]
|
||||
then
|
||||
r="|MERGING"
|
||||
b="$(git symbolic-ref HEAD 2>/dev/null)"
|
||||
else
|
||||
printf " (%s)" "${b##refs/heads/}"
|
||||
if [ -f $g/BISECT_LOG ]
|
||||
then
|
||||
r="|BISECTING"
|
||||
fi
|
||||
if ! b="$(git symbolic-ref HEAD 2>/dev/null)"
|
||||
then
|
||||
b="$(cut -c1-7 $g/HEAD)..."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
printf "$1" "${b##refs/heads/}$r"
|
||||
else
|
||||
printf " (%s)" "${b##refs/heads/}$r"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -105,6 +105,13 @@ selected element from l."
|
||||
(setq ,l (remove e ,l))
|
||||
e))
|
||||
|
||||
(defvar git-blame-log-oneline-format
|
||||
"format:[%cr] %cn: %s"
|
||||
"*Formatting option used for describing current line in the minibuffer.
|
||||
|
||||
This option is used to pass to git log --pretty= command-line option,
|
||||
and describe which commit the current line was made.")
|
||||
|
||||
(defvar git-blame-dark-colors
|
||||
(git-blame-color-scale "0c" "04" "24" "1c" "2c" "34" "14" "3c")
|
||||
"*List of colors (format #RGB) to use in a dark environment.
|
||||
@@ -371,7 +378,8 @@ See also function `git-blame-mode'."
|
||||
(defun git-describe-commit (hash)
|
||||
(with-temp-buffer
|
||||
(call-process "git" nil t nil
|
||||
"log" "-1" "--pretty=oneline"
|
||||
"log" "-1"
|
||||
(concat "--pretty=" git-blame-log-oneline-format)
|
||||
hash)
|
||||
(buffer-substring (point-min) (1- (point-max)))))
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
;;
|
||||
;; TODO
|
||||
;; - portability to XEmacs
|
||||
;; - better handling of subprocess errors
|
||||
;; - diff against other branch
|
||||
;; - renaming files from the status buffer
|
||||
;; - creating tags
|
||||
@@ -191,6 +190,18 @@ if there is already one that displays the same directory."
|
||||
(append (git-get-env-strings env) (list "git") args))
|
||||
(apply #'call-process "git" nil buffer nil args)))
|
||||
|
||||
(defun git-call-process-display-error (&rest args)
|
||||
"Wrapper for call-process that displays error messages."
|
||||
(let* ((dir default-directory)
|
||||
(buffer (get-buffer-create "*Git Command Output*"))
|
||||
(ok (with-current-buffer buffer
|
||||
(let ((default-directory dir)
|
||||
(buffer-read-only nil))
|
||||
(erase-buffer)
|
||||
(eq 0 (apply 'call-process "git" nil (list buffer t) nil args))))))
|
||||
(unless ok (display-message-or-buffer buffer))
|
||||
ok))
|
||||
|
||||
(defun git-call-process-env-string (env &rest args)
|
||||
"Wrapper for call-process that sets environment strings,
|
||||
and returns the process output as a string."
|
||||
@@ -377,7 +388,7 @@ and returns the process output as a string."
|
||||
(when reason
|
||||
(push reason args)
|
||||
(push "-m" args))
|
||||
(eq 0 (apply #'git-call-process-env nil nil "update-ref" args))))
|
||||
(apply 'git-call-process-display-error "update-ref" args)))
|
||||
|
||||
(defun git-read-tree (tree &optional index-file)
|
||||
"Read a tree into the index file."
|
||||
@@ -558,12 +569,15 @@ and returns the process output as a string."
|
||||
(?\100 " (type change file -> subproject)")
|
||||
(?\120 " (type change symlink -> subproject)")
|
||||
(t " (subproject)")))
|
||||
(?\110 nil) ;; directory (internal, not a real git state)
|
||||
(?\000 ;; deleted or unknown
|
||||
(case old-type
|
||||
(?\120 " (symlink)")
|
||||
(?\160 " (subproject)")))
|
||||
(t (format " (unknown type %o)" new-type)))))
|
||||
(if str (propertize str 'face 'git-status-face) "")))
|
||||
(cond (str (propertize str 'face 'git-status-face))
|
||||
((eq new-type ?\110) "/")
|
||||
(t ""))))
|
||||
|
||||
(defun git-rename-as-string (info)
|
||||
"Return a string describing the copy or rename associated with INFO, or an empty string if none."
|
||||
@@ -666,9 +680,11 @@ Return the list of files that haven't been handled."
|
||||
(with-temp-buffer
|
||||
(apply #'git-call-process-env t nil "ls-files" "-z" (append options (list "--") files))
|
||||
(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)))
|
||||
(push (git-create-fileinfo default-state name) infolist)
|
||||
(push (git-create-fileinfo default-state name 0
|
||||
(if (string-equal "/" (match-string 2)) (lsh ?\110 9) 0))
|
||||
infolist)
|
||||
(setq files (delete name files)))))
|
||||
(git-insert-info-list status infolist)
|
||||
files))
|
||||
@@ -713,7 +729,7 @@ Return the list of files that haven't been handled."
|
||||
(defun git-run-ls-files-with-excludes (status files default-state &rest options)
|
||||
"Run git-ls-files on FILES with appropriate --exclude-from options."
|
||||
(let ((exclude-files (git-get-exclude-files)))
|
||||
(apply #'git-run-ls-files status files default-state
|
||||
(apply #'git-run-ls-files status files default-state "--directory"
|
||||
(concat "--exclude-per-directory=" git-per-dir-ignore-file)
|
||||
(append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
|
||||
|
||||
@@ -735,6 +751,27 @@ Return the list of files that haven't been handled."
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)))
|
||||
|
||||
(defun git-mark-files (status files)
|
||||
"Mark all the specified FILES, and unmark the others."
|
||||
(setq files (sort files #'string-lessp))
|
||||
(let ((file (and files (pop files)))
|
||||
(node (ewoc-nth status 0)))
|
||||
(while node
|
||||
(let ((info (ewoc-data node)))
|
||||
(if (and file (string-equal (git-fileinfo->name info) file))
|
||||
(progn
|
||||
(unless (git-fileinfo->marked info)
|
||||
(setf (git-fileinfo->marked info) t)
|
||||
(setf (git-fileinfo->needs-refresh info) t))
|
||||
(setq file (pop files))
|
||||
(setq node (ewoc-next status node)))
|
||||
(when (git-fileinfo->marked info)
|
||||
(setf (git-fileinfo->marked info) nil)
|
||||
(setf (git-fileinfo->needs-refresh info) t))
|
||||
(if (and file (string-lessp file (git-fileinfo->name info)))
|
||||
(setq file (pop files))
|
||||
(setq node (ewoc-next status node))))))))
|
||||
|
||||
(defun git-marked-files ()
|
||||
"Return a list of all marked files, or if none a list containing just the file at cursor position."
|
||||
(unless git-status (error "Not in git-status buffer."))
|
||||
@@ -840,16 +877,17 @@ Return the list of files that haven't been handled."
|
||||
(if (or (not (string-equal tree head-tree))
|
||||
(yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? "))
|
||||
(let ((commit (git-commit-tree buffer tree head)))
|
||||
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
|
||||
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
|
||||
(with-current-buffer buffer (erase-buffer))
|
||||
(git-update-status-files (git-get-filenames files) 'uptodate)
|
||||
(git-call-process-env nil nil "rerere")
|
||||
(git-call-process-env nil nil "gc" "--auto")
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)
|
||||
(message "Committed %s." commit)
|
||||
(git-run-hook "post-commit" nil))
|
||||
(when commit
|
||||
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
|
||||
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
|
||||
(with-current-buffer buffer (erase-buffer))
|
||||
(git-update-status-files (git-get-filenames files) 'uptodate)
|
||||
(git-call-process-env nil nil "rerere")
|
||||
(git-call-process-env nil nil "gc" "--auto")
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)
|
||||
(message "Committed %s." commit)
|
||||
(git-run-hook "post-commit" nil)))
|
||||
(message "Commit aborted."))))
|
||||
(message "No files to commit.")))
|
||||
(delete-file index-file))))))
|
||||
@@ -957,11 +995,12 @@ Return the list of files that haven't been handled."
|
||||
"Add marked file(s) to the index cache."
|
||||
(interactive)
|
||||
(let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
|
||||
;; FIXME: add support for directories
|
||||
(unless files
|
||||
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
|
||||
(apply #'git-call-process-env nil nil "update-index" "--add" "--" files)
|
||||
(git-update-status-files files 'uptodate)
|
||||
(git-success-message "Added" files)))
|
||||
(when (apply 'git-call-process-display-error "update-index" "--add" "--" files)
|
||||
(git-update-status-files files 'uptodate)
|
||||
(git-success-message "Added" files))))
|
||||
|
||||
(defun git-ignore-file ()
|
||||
"Add marked file(s) to the ignore list."
|
||||
@@ -983,16 +1022,19 @@ Return the list of files that haven't been handled."
|
||||
(format "Remove %d file%s? " (length files) (if (> (length files) 1) "s" "")))
|
||||
(progn
|
||||
(dolist (name files)
|
||||
(when (file-exists-p name) (delete-file name)))
|
||||
(apply #'git-call-process-env nil nil "update-index" "--remove" "--" files)
|
||||
(git-update-status-files files nil)
|
||||
(git-success-message "Removed" files))
|
||||
(ignore-errors
|
||||
(if (file-directory-p name)
|
||||
(delete-directory name)
|
||||
(delete-file name))))
|
||||
(when (apply 'git-call-process-display-error "update-index" "--remove" "--" files)
|
||||
(git-update-status-files files nil)
|
||||
(git-success-message "Removed" files)))
|
||||
(message "Aborting"))))
|
||||
|
||||
(defun git-revert-file ()
|
||||
"Revert changes to the marked file(s)."
|
||||
(interactive)
|
||||
(let ((files (git-marked-files))
|
||||
(let ((files (git-marked-files-state 'added 'deleted 'modified 'unmerged))
|
||||
added modified)
|
||||
(when (and files
|
||||
(yes-or-no-p
|
||||
@@ -1003,21 +1045,31 @@ Return the list of files that haven't been handled."
|
||||
('deleted (push (git-fileinfo->name info) modified))
|
||||
('unmerged (push (git-fileinfo->name info) modified))
|
||||
('modified (push (git-fileinfo->name info) modified))))
|
||||
(when added
|
||||
(apply #'git-call-process-env nil nil "update-index" "--force-remove" "--" added))
|
||||
(when modified
|
||||
(apply #'git-call-process-env nil nil "checkout" "HEAD" modified))
|
||||
(git-update-status-files (append added modified) 'uptodate)
|
||||
(git-success-message "Reverted" (git-get-filenames files)))))
|
||||
;; check if a buffer contains one of the files and isn't saved
|
||||
(dolist (file modified)
|
||||
(let ((buffer (get-file-buffer file)))
|
||||
(when (and buffer (buffer-modified-p buffer))
|
||||
(error "Buffer %s is modified. Please kill or save modified buffers before reverting." (buffer-name buffer)))))
|
||||
(let ((ok (and
|
||||
(or (not added)
|
||||
(apply 'git-call-process-display-error "update-index" "--force-remove" "--" added))
|
||||
(or (not modified)
|
||||
(apply 'git-call-process-display-error "checkout" "HEAD" modified)))))
|
||||
(git-update-status-files (append added modified) 'uptodate)
|
||||
(when ok
|
||||
(dolist (file modified)
|
||||
(let ((buffer (get-file-buffer file)))
|
||||
(when buffer (with-current-buffer buffer (revert-buffer t t t)))))
|
||||
(git-success-message "Reverted" (git-get-filenames files)))))))
|
||||
|
||||
(defun git-resolve-file ()
|
||||
"Resolve conflicts in marked file(s)."
|
||||
(interactive)
|
||||
(let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
|
||||
(when files
|
||||
(apply #'git-call-process-env nil nil "update-index" "--" files)
|
||||
(git-update-status-files files 'uptodate)
|
||||
(git-success-message "Resolved" files))))
|
||||
(when (apply 'git-call-process-display-error "update-index" "--" files)
|
||||
(git-update-status-files files 'uptodate)
|
||||
(git-success-message "Resolved" files)))))
|
||||
|
||||
(defun git-remove-handled ()
|
||||
"Remove handled files from the status list."
|
||||
@@ -1063,6 +1115,16 @@ Return the list of files that haven't been handled."
|
||||
(message "Inserting unknown files...done"))
|
||||
(git-remove-handled)))
|
||||
|
||||
(defun git-expand-directory (info)
|
||||
"Expand the directory represented by INFO to list its files."
|
||||
(when (eq (lsh (git-fileinfo->new-perm info) -9) ?\110)
|
||||
(let ((dir (git-fileinfo->name info)))
|
||||
(git-set-filenames-state git-status (list dir) nil)
|
||||
(git-run-ls-files-with-excludes git-status (list (concat dir "/")) 'unknown "-o")
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)
|
||||
t)))
|
||||
|
||||
(defun git-setup-diff-buffer (buffer)
|
||||
"Setup a buffer for displaying a diff."
|
||||
(let ((dir default-directory))
|
||||
@@ -1199,7 +1261,8 @@ Return the list of files that haven't been handled."
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "\n+\\'" nil t)
|
||||
(replace-match "\n" t t))
|
||||
(when sign-off (git-append-sign-off committer-name committer-email)))))
|
||||
(when sign-off (git-append-sign-off committer-name committer-email)))
|
||||
buffer))
|
||||
|
||||
(defun git-commit-file ()
|
||||
"Commit the marked file(s), asking for a commit message."
|
||||
@@ -1232,14 +1295,61 @@ Return the list of files that haven't been handled."
|
||||
(setq buffer-file-coding-system coding-system)
|
||||
(re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t))))
|
||||
|
||||
(defun git-setup-commit-buffer (commit)
|
||||
"Setup the commit buffer with the contents of COMMIT."
|
||||
(let (author-name author-email subject date msg)
|
||||
(with-temp-buffer
|
||||
(let ((coding-system (git-get-logoutput-coding-system)))
|
||||
(git-call-process-env t nil "log" "-1" commit)
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Author: *\\(.*\\) <\\(.*\\)>$" nil t)
|
||||
(setq author-name (match-string 1))
|
||||
(setq author-email (match-string 2)))
|
||||
(when (re-search-forward "^Date: *\\(.*\\)$" nil t)
|
||||
(setq date (match-string 1)))
|
||||
(while (re-search-forward "^ \\(.*\\)$" nil t)
|
||||
(push (match-string 1) msg))
|
||||
(setq msg (nreverse msg))
|
||||
(setq subject (pop msg))
|
||||
(while (and msg (zerop (length (car msg))) (pop msg)))))
|
||||
(git-setup-log-buffer (get-buffer-create "*git-commit*")
|
||||
author-name author-email subject date
|
||||
(mapconcat #'identity msg "\n"))))
|
||||
|
||||
(defun git-get-commit-files (commit)
|
||||
"Retrieve the list of files modified by COMMIT."
|
||||
(let (files)
|
||||
(with-temp-buffer
|
||||
(git-call-process-env t nil "diff-tree" "-r" "-z" "--name-only" "--no-commit-id" commit)
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
|
||||
(push (match-string 1) files)))
|
||||
files))
|
||||
|
||||
(defun git-amend-commit ()
|
||||
"Undo the last commit on HEAD, and set things up to commit an
|
||||
amended version of it."
|
||||
(interactive)
|
||||
(unless git-status (error "Not in git-status buffer."))
|
||||
(when (git-empty-db-p) (error "No commit to amend."))
|
||||
(let* ((commit (git-rev-parse "HEAD"))
|
||||
(files (git-get-commit-files commit)))
|
||||
(when (git-call-process-display-error "reset" "--soft" "HEAD^")
|
||||
(git-update-status-files (copy-sequence files) 'uptodate)
|
||||
(git-mark-files git-status files)
|
||||
(git-refresh-files)
|
||||
(git-setup-commit-buffer commit)
|
||||
(git-commit-file))))
|
||||
|
||||
(defun git-find-file ()
|
||||
"Visit the current file in its own buffer."
|
||||
(interactive)
|
||||
(unless git-status (error "Not in git-status buffer."))
|
||||
(let ((info (ewoc-data (ewoc-locate git-status))))
|
||||
(find-file (git-fileinfo->name info))
|
||||
(when (eq 'unmerged (git-fileinfo->state info))
|
||||
(smerge-mode 1))))
|
||||
(unless (git-expand-directory info)
|
||||
(find-file (git-fileinfo->name info))
|
||||
(when (eq 'unmerged (git-fileinfo->state info))
|
||||
(smerge-mode 1)))))
|
||||
|
||||
(defun git-find-file-other-window ()
|
||||
"Visit the current file in its own buffer in another window."
|
||||
@@ -1309,6 +1419,7 @@ Return the list of files that haven't been handled."
|
||||
|
||||
(unless git-status-mode-map
|
||||
(let ((map (make-keymap))
|
||||
(commit-map (make-sparse-keymap))
|
||||
(diff-map (make-sparse-keymap))
|
||||
(toggle-map (make-sparse-keymap)))
|
||||
(suppress-keymap map)
|
||||
@@ -1317,6 +1428,7 @@ Return the list of files that haven't been handled."
|
||||
(define-key map " " 'git-next-file)
|
||||
(define-key map "a" 'git-add-file)
|
||||
(define-key map "c" 'git-commit-file)
|
||||
(define-key map "\C-c" commit-map)
|
||||
(define-key map "d" diff-map)
|
||||
(define-key map "=" 'git-diff-file)
|
||||
(define-key map "f" 'git-find-file)
|
||||
@@ -1342,6 +1454,8 @@ Return the list of files that haven't been handled."
|
||||
(define-key map "x" 'git-remove-handled)
|
||||
(define-key map "\C-?" 'git-unmark-file-up)
|
||||
(define-key map "\M-\C-?" 'git-unmark-all)
|
||||
; the commit submap
|
||||
(define-key commit-map "\C-a" 'git-amend-commit)
|
||||
; the diff submap
|
||||
(define-key diff-map "b" 'git-diff-file-base)
|
||||
(define-key diff-map "c" 'git-diff-file-combined)
|
||||
|
||||
@@ -469,9 +469,7 @@ class P4Submit(Command):
|
||||
optparse.make_option("--origin", dest="origin"),
|
||||
optparse.make_option("--reset", action="store_true", dest="reset"),
|
||||
optparse.make_option("--log-substitutions", dest="substFile"),
|
||||
optparse.make_option("--dry-run", action="store_true"),
|
||||
optparse.make_option("--direct", dest="directSubmit", action="store_true"),
|
||||
optparse.make_option("--trust-me-like-a-fool", dest="trustMeLikeAFool", action="store_true"),
|
||||
optparse.make_option("-M", dest="detectRename", action="store_true"),
|
||||
]
|
||||
self.description = "Submit changes from git to the perforce depot."
|
||||
@@ -479,12 +477,10 @@ class P4Submit(Command):
|
||||
self.firstTime = True
|
||||
self.reset = False
|
||||
self.interactive = True
|
||||
self.dryRun = False
|
||||
self.substFile = ""
|
||||
self.firstTime = True
|
||||
self.origin = ""
|
||||
self.directSubmit = False
|
||||
self.trustMeLikeAFool = False
|
||||
self.detectRename = False
|
||||
self.verbose = False
|
||||
self.isWindows = (platform.system() == "Windows")
|
||||
@@ -681,57 +677,30 @@ class P4Submit(Command):
|
||||
separatorLine += "\r"
|
||||
separatorLine += "\n"
|
||||
|
||||
response = "e"
|
||||
if self.trustMeLikeAFool:
|
||||
response = "y"
|
||||
[handle, fileName] = tempfile.mkstemp()
|
||||
tmpFile = os.fdopen(handle, "w+")
|
||||
tmpFile.write(submitTemplate + separatorLine + diff)
|
||||
tmpFile.close()
|
||||
defaultEditor = "vi"
|
||||
if platform.system() == "Windows":
|
||||
defaultEditor = "notepad"
|
||||
editor = os.environ.get("EDITOR", defaultEditor);
|
||||
system(editor + " " + fileName)
|
||||
tmpFile = open(fileName, "rb")
|
||||
message = tmpFile.read()
|
||||
tmpFile.close()
|
||||
os.remove(fileName)
|
||||
submitTemplate = message[:message.index(separatorLine)]
|
||||
if self.isWindows:
|
||||
submitTemplate = submitTemplate.replace("\r\n", "\n")
|
||||
|
||||
firstIteration = True
|
||||
while response == "e":
|
||||
if not firstIteration:
|
||||
response = raw_input("Do you want to submit this change? [y]es/[e]dit/[n]o/[s]kip ")
|
||||
firstIteration = False
|
||||
if response == "e":
|
||||
[handle, fileName] = tempfile.mkstemp()
|
||||
tmpFile = os.fdopen(handle, "w+")
|
||||
tmpFile.write(submitTemplate + separatorLine + diff)
|
||||
tmpFile.close()
|
||||
defaultEditor = "vi"
|
||||
if platform.system() == "Windows":
|
||||
defaultEditor = "notepad"
|
||||
editor = os.environ.get("EDITOR", defaultEditor);
|
||||
system(editor + " " + fileName)
|
||||
tmpFile = open(fileName, "rb")
|
||||
message = tmpFile.read()
|
||||
tmpFile.close()
|
||||
os.remove(fileName)
|
||||
submitTemplate = message[:message.index(separatorLine)]
|
||||
if self.isWindows:
|
||||
submitTemplate = submitTemplate.replace("\r\n", "\n")
|
||||
if self.directSubmit:
|
||||
print "Submitting to git first"
|
||||
os.chdir(self.oldWorkingDirectory)
|
||||
write_pipe("git commit -a -F -", submitTemplate)
|
||||
os.chdir(self.clientPath)
|
||||
|
||||
if response == "y" or response == "yes":
|
||||
if self.dryRun:
|
||||
print submitTemplate
|
||||
raw_input("Press return to continue...")
|
||||
else:
|
||||
if self.directSubmit:
|
||||
print "Submitting to git first"
|
||||
os.chdir(self.oldWorkingDirectory)
|
||||
write_pipe("git commit -a -F -", submitTemplate)
|
||||
os.chdir(self.clientPath)
|
||||
|
||||
write_pipe("p4 submit -i", submitTemplate)
|
||||
elif response == "s":
|
||||
for f in editedFiles:
|
||||
system("p4 revert \"%s\"" % f);
|
||||
for f in filesToAdd:
|
||||
system("p4 revert \"%s\"" % f);
|
||||
system("rm %s" %f)
|
||||
for f in filesToDelete:
|
||||
system("p4 delete \"%s\"" % f);
|
||||
return
|
||||
else:
|
||||
print "Not submitting!"
|
||||
self.interactive = False
|
||||
write_pipe("p4 submit -i", submitTemplate)
|
||||
else:
|
||||
fileName = "submit.txt"
|
||||
file = open(fileName, "w+")
|
||||
@@ -828,10 +797,8 @@ class P4Submit(Command):
|
||||
sync = P4Sync()
|
||||
sync.run([])
|
||||
|
||||
response = raw_input("Do you want to rebase current HEAD from Perforce now using git-p4 rebase? [y]es/[n]o ")
|
||||
if response == "y" or response == "yes":
|
||||
rebase = P4Rebase()
|
||||
rebase.rebase()
|
||||
rebase = P4Rebase()
|
||||
rebase.rebase()
|
||||
os.remove(self.configFile)
|
||||
|
||||
return True
|
||||
@@ -964,9 +931,13 @@ class P4Sync(Command):
|
||||
stat = filedata[j]
|
||||
j += 1
|
||||
text = ''
|
||||
while j < len(filedata) and filedata[j]['code'] in ('text',
|
||||
'binary'):
|
||||
text += filedata[j]['data']
|
||||
while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
|
||||
tmp = filedata[j]['data']
|
||||
if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
|
||||
tmp = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', tmp)
|
||||
elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
|
||||
tmp = re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', tmp)
|
||||
text += tmp
|
||||
j += 1
|
||||
|
||||
|
||||
@@ -1640,6 +1611,11 @@ class P4Rebase(Command):
|
||||
return self.rebase()
|
||||
|
||||
def rebase(self):
|
||||
if os.system("git update-index --refresh") != 0:
|
||||
die("Some files in your working directory are modified and different than what is in your index. You can use git update-index <filename> to bring the index up-to-date or stash away all your changes with git stash.");
|
||||
if len(read_pipe("git diff-index HEAD --")) > 0:
|
||||
die("You have uncommited changes. Please commit them before rebasing or stash them away with git stash.");
|
||||
|
||||
[upstream, settings] = findUpstreamBranchPoint()
|
||||
if len(upstream) == 0:
|
||||
die("Cannot find upstream branchpoint for rebase")
|
||||
@@ -1670,7 +1646,7 @@ class P4Clone(P4Sync):
|
||||
depotPath = args[0]
|
||||
depotDir = re.sub("(@[^@]*)$", "", depotPath)
|
||||
depotDir = re.sub("(#[^#]*)$", "", depotDir)
|
||||
depotDir = re.sub(r"\.\.\.$,", "", depotDir)
|
||||
depotDir = re.sub(r"\.\.\.$", "", depotDir)
|
||||
depotDir = re.sub(r"/$", "", depotDir)
|
||||
return os.path.split(depotDir)[1]
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ hgparents["0"] = (None, None)
|
||||
hgbranch["0"] = "master"
|
||||
for cset in range(1, int(tip) + 1):
|
||||
hgchildren[str(cset)] = ()
|
||||
prnts = os.popen('hg log -r %d --template "{parents}"' % cset).read().split(' ')
|
||||
prnts = os.popen('hg log -r %d --template "{parents}"' % cset).read().strip().split(' ')
|
||||
prnts = map(lambda x: x[:x.find(':')], prnts)
|
||||
if prnts[0] != '':
|
||||
parent = prnts[0].strip()
|
||||
|
||||
51
convert.c
51
convert.c
@@ -85,8 +85,39 @@ static int is_binary(unsigned long size, struct text_stat *stats)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_safe_crlf(const char *path, int action,
|
||||
struct text_stat *stats, enum safe_crlf checksafe)
|
||||
{
|
||||
if (!checksafe)
|
||||
return;
|
||||
|
||||
if (action == CRLF_INPUT || auto_crlf <= 0) {
|
||||
/*
|
||||
* CRLFs would not be restored by checkout:
|
||||
* check if we'd remove CRLFs
|
||||
*/
|
||||
if (stats->crlf) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("CRLF will be replaced by LF in %s.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("CRLF would be replaced by LF in %s.", path);
|
||||
}
|
||||
} else if (auto_crlf > 0) {
|
||||
/*
|
||||
* CRLFs would be added by checkout:
|
||||
* check if we have "naked" LFs
|
||||
*/
|
||||
if (stats->lf != stats->crlf) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("LF will be replaced by CRLF in %s", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("LF would be replaced by CRLF in %s", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int crlf_to_git(const char *path, const char *src, size_t len,
|
||||
struct strbuf *buf, int action)
|
||||
struct strbuf *buf, int action, enum safe_crlf checksafe)
|
||||
{
|
||||
struct text_stat stats;
|
||||
char *dst;
|
||||
@@ -95,9 +126,6 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
||||
return 0;
|
||||
|
||||
gather_stats(src, len, &stats);
|
||||
/* No CR? Nothing to convert, regardless. */
|
||||
if (!stats.cr)
|
||||
return 0;
|
||||
|
||||
if (action == CRLF_GUESS) {
|
||||
/*
|
||||
@@ -115,6 +143,12 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
check_safe_crlf(path, action, &stats, checksafe);
|
||||
|
||||
/* Optimization: No CR? Nothing to convert, regardless. */
|
||||
if (!stats.cr)
|
||||
return 0;
|
||||
|
||||
/* only grow if not in place */
|
||||
if (strbuf_avail(buf) + buf->len < len)
|
||||
strbuf_grow(buf, len - buf->len);
|
||||
@@ -326,14 +360,14 @@ static int read_convert_config(const char *var, const char *value)
|
||||
|
||||
if (!strcmp("smudge", ep)) {
|
||||
if (!value)
|
||||
return error("%s: lacks value", var);
|
||||
return config_error_nonbool(var);
|
||||
drv->smudge = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("clean", ep)) {
|
||||
if (!value)
|
||||
return error("%s: lacks value", var);
|
||||
return config_error_nonbool(var);
|
||||
drv->clean = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
@@ -536,7 +570,8 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
|
||||
return !!ATTR_TRUE(value);
|
||||
}
|
||||
|
||||
int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst)
|
||||
int convert_to_git(const char *path, const char *src, size_t len,
|
||||
struct strbuf *dst, enum safe_crlf checksafe)
|
||||
{
|
||||
struct git_attr_check check[3];
|
||||
int crlf = CRLF_GUESS;
|
||||
@@ -558,7 +593,7 @@ int convert_to_git(const char *path, const char *src, size_t len, struct strbuf
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
}
|
||||
ret |= crlf_to_git(path, src, len, dst, crlf);
|
||||
ret |= crlf_to_git(path, src, len, dst, crlf, checksafe);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
|
||||
273
diff-lib.c
273
diff-lib.c
@@ -9,6 +9,7 @@
|
||||
#include "revision.h"
|
||||
#include "cache-tree.h"
|
||||
#include "path-list.h"
|
||||
#include "unpack-trees.h"
|
||||
|
||||
/*
|
||||
* diff-files
|
||||
@@ -37,7 +38,7 @@ static int get_mode(const char *path, int *mode)
|
||||
if (!path || !strcmp(path, "/dev/null"))
|
||||
*mode = 0;
|
||||
else if (!strcmp(path, "-"))
|
||||
*mode = ntohl(create_ce_mode(0666));
|
||||
*mode = create_ce_mode(0666);
|
||||
else if (stat(path, &st))
|
||||
return error("Could not access '%s'", path);
|
||||
else
|
||||
@@ -384,7 +385,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
dpath->mode = ntohl(ce_mode_from_stat(ce, st.st_mode));
|
||||
dpath->mode = ce_mode_from_stat(ce, st.st_mode);
|
||||
|
||||
while (i < entries) {
|
||||
struct cache_entry *nce = active_cache[i];
|
||||
@@ -398,10 +399,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
|
||||
*/
|
||||
stage = ce_stage(nce);
|
||||
if (2 <= stage) {
|
||||
int mode = ntohl(nce->ce_mode);
|
||||
int mode = nce->ce_mode;
|
||||
num_compare_stages++;
|
||||
hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
|
||||
dpath->parent[stage-2].mode = ntohl(ce_mode_from_stat(nce, mode));
|
||||
dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
|
||||
dpath->parent[stage-2].status =
|
||||
DIFF_STATUS_MODIFIED;
|
||||
}
|
||||
@@ -435,6 +436,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ce_uptodate(ce))
|
||||
continue;
|
||||
if (lstat(ce->name, &st) < 0) {
|
||||
if (errno != ENOENT && errno != ENOTDIR) {
|
||||
perror(ce->name);
|
||||
@@ -442,15 +445,15 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
|
||||
}
|
||||
if (silent_on_removed)
|
||||
continue;
|
||||
diff_addremove(&revs->diffopt, '-', ntohl(ce->ce_mode),
|
||||
diff_addremove(&revs->diffopt, '-', ce->ce_mode,
|
||||
ce->sha1, ce->name, NULL);
|
||||
continue;
|
||||
}
|
||||
changed = ce_match_stat(ce, &st, ce_option);
|
||||
if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
|
||||
continue;
|
||||
oldmode = ntohl(ce->ce_mode);
|
||||
newmode = ntohl(ce_mode_from_stat(ce, st.st_mode));
|
||||
oldmode = ce->ce_mode;
|
||||
newmode = ce_mode_from_stat(ce, st.st_mode);
|
||||
diff_change(&revs->diffopt, oldmode, newmode,
|
||||
ce->sha1, (changed ? null_sha1 : ce->sha1),
|
||||
ce->name, NULL);
|
||||
@@ -471,7 +474,7 @@ static void diff_index_show_file(struct rev_info *revs,
|
||||
struct cache_entry *ce,
|
||||
unsigned char *sha1, unsigned int mode)
|
||||
{
|
||||
diff_addremove(&revs->diffopt, prefix[0], ntohl(mode),
|
||||
diff_addremove(&revs->diffopt, prefix[0], mode,
|
||||
sha1, ce->name, NULL);
|
||||
}
|
||||
|
||||
@@ -550,14 +553,14 @@ static int show_modified(struct rev_info *revs,
|
||||
p->len = pathlen;
|
||||
memcpy(p->path, new->name, pathlen);
|
||||
p->path[pathlen] = 0;
|
||||
p->mode = ntohl(mode);
|
||||
p->mode = mode;
|
||||
hashclr(p->sha1);
|
||||
memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
|
||||
p->parent[0].status = DIFF_STATUS_MODIFIED;
|
||||
p->parent[0].mode = ntohl(new->ce_mode);
|
||||
p->parent[0].mode = new->ce_mode;
|
||||
hashcpy(p->parent[0].sha1, new->sha1);
|
||||
p->parent[1].status = DIFF_STATUS_MODIFIED;
|
||||
p->parent[1].mode = ntohl(old->ce_mode);
|
||||
p->parent[1].mode = old->ce_mode;
|
||||
hashcpy(p->parent[1].sha1, old->sha1);
|
||||
show_combined_diff(p, 2, revs->dense_combined_merges, revs);
|
||||
free(p);
|
||||
@@ -569,89 +572,11 @@ static int show_modified(struct rev_info *revs,
|
||||
!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
|
||||
return 0;
|
||||
|
||||
mode = ntohl(mode);
|
||||
oldmode = ntohl(oldmode);
|
||||
|
||||
diff_change(&revs->diffopt, oldmode, mode,
|
||||
old->sha1, sha1, old->name, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int diff_cache(struct rev_info *revs,
|
||||
struct cache_entry **ac, int entries,
|
||||
const char **pathspec,
|
||||
int cached, int match_missing)
|
||||
{
|
||||
while (entries) {
|
||||
struct cache_entry *ce = *ac;
|
||||
int same = (entries > 1) && ce_same_name(ce, ac[1]);
|
||||
|
||||
if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
|
||||
DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
|
||||
break;
|
||||
|
||||
if (!ce_path_match(ce, pathspec))
|
||||
goto skip_entry;
|
||||
|
||||
switch (ce_stage(ce)) {
|
||||
case 0:
|
||||
/* No stage 1 entry? That means it's a new file */
|
||||
if (!same) {
|
||||
show_new_file(revs, ce, cached, match_missing);
|
||||
break;
|
||||
}
|
||||
/* Show difference between old and new */
|
||||
show_modified(revs, ac[1], ce, 1,
|
||||
cached, match_missing);
|
||||
break;
|
||||
case 1:
|
||||
/* No stage 3 (merge) entry?
|
||||
* That means it's been deleted.
|
||||
*/
|
||||
if (!same) {
|
||||
diff_index_show_file(revs, "-", ce,
|
||||
ce->sha1, ce->ce_mode);
|
||||
break;
|
||||
}
|
||||
/* We come here with ce pointing at stage 1
|
||||
* (original tree) and ac[1] pointing at stage
|
||||
* 3 (unmerged). show-modified with
|
||||
* report-missing set to false does not say the
|
||||
* file is deleted but reports true if work
|
||||
* tree does not have it, in which case we
|
||||
* fall through to report the unmerged state.
|
||||
* Otherwise, we show the differences between
|
||||
* the original tree and the work tree.
|
||||
*/
|
||||
if (!cached &&
|
||||
!show_modified(revs, ce, ac[1], 0,
|
||||
cached, match_missing))
|
||||
break;
|
||||
diff_unmerge(&revs->diffopt, ce->name,
|
||||
ntohl(ce->ce_mode), ce->sha1);
|
||||
break;
|
||||
case 3:
|
||||
diff_unmerge(&revs->diffopt, ce->name,
|
||||
0, null_sha1);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("impossible cache entry stage");
|
||||
}
|
||||
|
||||
skip_entry:
|
||||
/*
|
||||
* Ignore all the different stages for this file,
|
||||
* we've handled the relevant cases now.
|
||||
*/
|
||||
do {
|
||||
ac++;
|
||||
entries--;
|
||||
} while (entries && ce_same_name(ce, ac[0]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This turns all merge entries into "stage 3". That guarantees that
|
||||
* when we read in the new tree (into "stage 1"), we won't lose sight
|
||||
@@ -664,24 +589,137 @@ static void mark_merge_entries(void)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (!ce_stage(ce))
|
||||
continue;
|
||||
ce->ce_flags |= htons(CE_STAGEMASK);
|
||||
ce->ce_flags |= CE_STAGEMASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets a mix of an existing index and a tree, one pathname entry
|
||||
* at a time. The index entry may be a single stage-0 one, but it could
|
||||
* also be multiple unmerged entries (in which case idx_pos/idx_nr will
|
||||
* give you the position and number of entries in the index).
|
||||
*/
|
||||
static void do_oneway_diff(struct unpack_trees_options *o,
|
||||
struct cache_entry *idx,
|
||||
struct cache_entry *tree,
|
||||
int idx_pos, int idx_nr)
|
||||
{
|
||||
struct rev_info *revs = o->unpack_data;
|
||||
int match_missing, cached;
|
||||
|
||||
/*
|
||||
* Backward compatibility wart - "diff-index -m" does
|
||||
* not mean "do not ignore merges", but "match_missing".
|
||||
*
|
||||
* But with the revision flag parsing, that's found in
|
||||
* "!revs->ignore_merges".
|
||||
*/
|
||||
cached = o->index_only;
|
||||
match_missing = !revs->ignore_merges;
|
||||
|
||||
if (cached && idx && ce_stage(idx)) {
|
||||
if (tree)
|
||||
diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Something added to the tree?
|
||||
*/
|
||||
if (!tree) {
|
||||
show_new_file(revs, idx, cached, match_missing);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Something removed from the tree?
|
||||
*/
|
||||
if (!idx) {
|
||||
diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show difference between old and new */
|
||||
show_modified(revs, tree, idx, 1, cached, match_missing);
|
||||
}
|
||||
|
||||
/*
|
||||
* Count how many index entries go with the first one
|
||||
*/
|
||||
static inline int count_skip(const struct cache_entry *src, int pos)
|
||||
{
|
||||
int skip = 1;
|
||||
|
||||
/* We can only have multiple entries if the first one is not stage-0 */
|
||||
if (ce_stage(src)) {
|
||||
struct cache_entry **p = active_cache + pos;
|
||||
int namelen = ce_namelen(src);
|
||||
|
||||
for (;;) {
|
||||
const struct cache_entry *ce;
|
||||
pos++;
|
||||
if (pos >= active_nr)
|
||||
break;
|
||||
ce = *++p;
|
||||
if (ce_namelen(ce) != namelen)
|
||||
break;
|
||||
if (memcmp(ce->name, src->name, namelen))
|
||||
break;
|
||||
skip++;
|
||||
}
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
|
||||
/*
|
||||
* The unpack_trees() interface is designed for merging, so
|
||||
* the different source entries are designed primarily for
|
||||
* the source trees, with the old index being really mainly
|
||||
* used for being replaced by the result.
|
||||
*
|
||||
* For diffing, the index is more important, and we only have a
|
||||
* single tree.
|
||||
*
|
||||
* We're supposed to return how many index entries we want to skip.
|
||||
*
|
||||
* This wrapper makes it all more readable, and takes care of all
|
||||
* the fairly complex unpack_trees() semantic requirements, including
|
||||
* the skipping, the path matching, the type conflict cases etc.
|
||||
*/
|
||||
static int oneway_diff(struct cache_entry **src,
|
||||
struct unpack_trees_options *o,
|
||||
int index_pos)
|
||||
{
|
||||
int skip = 0;
|
||||
struct cache_entry *idx = src[0];
|
||||
struct cache_entry *tree = src[1];
|
||||
struct rev_info *revs = o->unpack_data;
|
||||
|
||||
if (index_pos >= 0)
|
||||
skip = count_skip(idx, index_pos);
|
||||
|
||||
/*
|
||||
* Unpack-trees generates a DF/conflict entry if
|
||||
* there was a directory in the index and a tree
|
||||
* in the tree. From a diff standpoint, that's a
|
||||
* delete of the tree and a create of the file.
|
||||
*/
|
||||
if (tree == o->df_conflict_entry)
|
||||
tree = NULL;
|
||||
|
||||
if (ce_path_match(idx ? idx : tree, revs->prune_data))
|
||||
do_oneway_diff(o, idx, tree, index_pos, skip);
|
||||
|
||||
return skip;
|
||||
}
|
||||
|
||||
int run_diff_index(struct rev_info *revs, int cached)
|
||||
{
|
||||
int ret;
|
||||
struct object *ent;
|
||||
struct tree *tree;
|
||||
const char *tree_name;
|
||||
int match_missing = 0;
|
||||
|
||||
/*
|
||||
* Backward compatibility wart - "diff-index -m" does
|
||||
* not mean "do not ignore merges", but totally different.
|
||||
*/
|
||||
if (!revs->ignore_merges)
|
||||
match_missing = 1;
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc t;
|
||||
|
||||
mark_merge_entries();
|
||||
|
||||
@@ -690,13 +728,20 @@ int run_diff_index(struct rev_info *revs, int cached)
|
||||
tree = parse_tree_indirect(ent->sha1);
|
||||
if (!tree)
|
||||
return error("bad tree object %s", tree_name);
|
||||
if (read_tree(tree, 1, revs->prune_data))
|
||||
return error("unable to read tree object %s", tree_name);
|
||||
ret = diff_cache(revs, active_cache, active_nr, revs->prune_data,
|
||||
cached, match_missing);
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.head_idx = 1;
|
||||
opts.index_only = cached;
|
||||
opts.merge = 1;
|
||||
opts.fn = oneway_diff;
|
||||
opts.unpack_data = revs;
|
||||
|
||||
init_tree_desc(&t, tree->buffer, tree->size);
|
||||
unpack_trees(1, &t, &opts);
|
||||
|
||||
diffcore_std(&revs->diffopt);
|
||||
diff_flush(&revs->diffopt);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
|
||||
@@ -706,6 +751,8 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
|
||||
int i;
|
||||
struct cache_entry **dst;
|
||||
struct cache_entry *last = NULL;
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc t;
|
||||
|
||||
/*
|
||||
* This is used by git-blame to run diff-cache internally;
|
||||
@@ -722,8 +769,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
|
||||
cache_tree_invalidate_path(active_cache_tree,
|
||||
ce->name);
|
||||
last = ce;
|
||||
ce->ce_mode = 0;
|
||||
ce->ce_flags &= ~htons(CE_STAGEMASK);
|
||||
ce->ce_flags |= CE_REMOVE;
|
||||
}
|
||||
*dst++ = ce;
|
||||
}
|
||||
@@ -734,8 +780,15 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
|
||||
tree = parse_tree_indirect(tree_sha1);
|
||||
if (!tree)
|
||||
die("bad tree object %s", sha1_to_hex(tree_sha1));
|
||||
if (read_tree(tree, 1, opt->paths))
|
||||
return error("unable to read tree %s", sha1_to_hex(tree_sha1));
|
||||
return diff_cache(&revs, active_cache, active_nr, revs.prune_data,
|
||||
1, 0);
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.head_idx = 1;
|
||||
opts.index_only = 1;
|
||||
opts.merge = 1;
|
||||
opts.fn = oneway_diff;
|
||||
opts.unpack_data = &revs;
|
||||
|
||||
init_tree_desc(&t, tree->buffer, tree->size);
|
||||
unpack_trees(1, &t, &opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
53
diff.c
53
diff.c
@@ -57,7 +57,7 @@ static int parse_diff_color_slot(const char *var, int ofs)
|
||||
static struct ll_diff_driver {
|
||||
const char *name;
|
||||
struct ll_diff_driver *next;
|
||||
char *cmd;
|
||||
const char *cmd;
|
||||
} *user_diff, **user_diff_tail;
|
||||
|
||||
/*
|
||||
@@ -86,10 +86,7 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
|
||||
user_diff_tail = &(drv->next);
|
||||
}
|
||||
|
||||
if (!value)
|
||||
return error("%s: lacks value", var);
|
||||
drv->cmd = strdup(value);
|
||||
return 0;
|
||||
return git_config_string(&(drv->cmd), var, value);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -158,16 +155,16 @@ int git_diff_ui_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "diff.external")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
external_diff_cmd_cfg = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!prefixcmp(var, "diff.")) {
|
||||
const char *ep = strrchr(var, '.');
|
||||
|
||||
if (ep != var + 4) {
|
||||
if (!strcmp(ep, ".command"))
|
||||
return parse_lldiff_command(var, ep, value);
|
||||
}
|
||||
if (ep != var + 4 && !strcmp(ep, ".command"))
|
||||
return parse_lldiff_command(var, ep, value);
|
||||
}
|
||||
|
||||
return git_diff_basic_config(var, value);
|
||||
@@ -177,6 +174,8 @@ int git_diff_basic_config(const char *var, const char *value)
|
||||
{
|
||||
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
|
||||
int slot = parse_diff_color_slot(var, 11);
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
color_parse(value, var, diff_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
@@ -184,8 +183,11 @@ int git_diff_basic_config(const char *var, const char *value)
|
||||
if (!prefixcmp(var, "diff.")) {
|
||||
const char *ep = strrchr(var, '.');
|
||||
if (ep != var + 4) {
|
||||
if (!strcmp(ep, ".funcname"))
|
||||
if (!strcmp(ep, ".funcname")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
return parse_funcname_pattern(var, ep, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1011,6 +1013,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
char *err;
|
||||
|
||||
if (line[0] == '+') {
|
||||
data->lineno++;
|
||||
data->status = check_and_emit_line(line + 1, len - 1,
|
||||
data->ws_rule, NULL, NULL, NULL, NULL);
|
||||
if (!data->status)
|
||||
@@ -1021,13 +1024,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
emit_line(set, reset, line, 1);
|
||||
(void)check_and_emit_line(line + 1, len - 1, data->ws_rule,
|
||||
stdout, set, reset, ws);
|
||||
data->lineno++;
|
||||
} else if (line[0] == ' ')
|
||||
data->lineno++;
|
||||
else if (line[0] == '@') {
|
||||
char *plus = strchr(line, '+');
|
||||
if (plus)
|
||||
data->lineno = strtol(plus, NULL, 10);
|
||||
data->lineno = strtol(plus, NULL, 10) - 1;
|
||||
else
|
||||
die("invalid diff");
|
||||
}
|
||||
@@ -1510,17 +1512,22 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
ce = active_cache[pos];
|
||||
if ((lstat(name, &st) < 0) ||
|
||||
!S_ISREG(st.st_mode) || /* careful! */
|
||||
ce_match_stat(ce, &st, 0) ||
|
||||
hashcmp(sha1, ce->sha1))
|
||||
return 0;
|
||||
/* we return 1 only when we can stat, it is a regular file,
|
||||
* stat information matches, and sha1 recorded in the cache
|
||||
* matches. I.e. we know the file in the work tree really is
|
||||
* the same as the <name, sha1> pair.
|
||||
|
||||
/*
|
||||
* This is not the sha1 we are looking for, or
|
||||
* unreusable because it is not a regular file.
|
||||
*/
|
||||
return 1;
|
||||
if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If ce matches the file in the work tree, we can reuse it.
|
||||
*/
|
||||
if (ce_uptodate(ce) ||
|
||||
(!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int populate_from_stdin(struct diff_filespec *s)
|
||||
@@ -1624,7 +1631,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
||||
* Convert from working tree format to canonical git format
|
||||
*/
|
||||
strbuf_init(&buf, 0);
|
||||
if (convert_to_git(s->path, s->data, s->size, &buf)) {
|
||||
if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
|
||||
size_t size = 0;
|
||||
munmap(s->data, s->size);
|
||||
s->should_munmap = 0;
|
||||
|
||||
53
dir.c
53
dir.c
@@ -17,6 +17,7 @@ struct path_simplify {
|
||||
static int read_directory_recursive(struct dir_struct *dir,
|
||||
const char *path, const char *base, int baselen,
|
||||
int check_only, const struct path_simplify *simplify);
|
||||
static int get_dtype(struct dirent *de, const char *path);
|
||||
|
||||
int common_prefix(const char **pathspec)
|
||||
{
|
||||
@@ -126,18 +127,34 @@ static int no_wildcard(const char *string)
|
||||
void add_exclude(const char *string, const char *base,
|
||||
int baselen, struct exclude_list *which)
|
||||
{
|
||||
struct exclude *x = xmalloc(sizeof (*x));
|
||||
struct exclude *x;
|
||||
size_t len;
|
||||
int to_exclude = 1;
|
||||
int flags = 0;
|
||||
|
||||
x->to_exclude = 1;
|
||||
if (*string == '!') {
|
||||
x->to_exclude = 0;
|
||||
to_exclude = 0;
|
||||
string++;
|
||||
}
|
||||
x->pattern = string;
|
||||
len = strlen(string);
|
||||
if (len && string[len - 1] == '/') {
|
||||
char *s;
|
||||
x = xmalloc(sizeof(*x) + len);
|
||||
s = (char*)(x+1);
|
||||
memcpy(s, string, len - 1);
|
||||
s[len - 1] = '\0';
|
||||
string = s;
|
||||
x->pattern = s;
|
||||
flags = EXC_FLAG_MUSTBEDIR;
|
||||
} else {
|
||||
x = xmalloc(sizeof(*x));
|
||||
x->pattern = string;
|
||||
}
|
||||
x->to_exclude = to_exclude;
|
||||
x->patternlen = strlen(string);
|
||||
x->base = base;
|
||||
x->baselen = baselen;
|
||||
x->flags = 0;
|
||||
x->flags = flags;
|
||||
if (!strchr(string, '/'))
|
||||
x->flags |= EXC_FLAG_NODIR;
|
||||
if (no_wildcard(string))
|
||||
@@ -261,7 +278,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
|
||||
* Return 1 for exclude, 0 for include and -1 for undecided.
|
||||
*/
|
||||
static int excluded_1(const char *pathname,
|
||||
int pathlen, const char *basename,
|
||||
int pathlen, const char *basename, int *dtype,
|
||||
struct exclude_list *el)
|
||||
{
|
||||
int i;
|
||||
@@ -272,6 +289,13 @@ static int excluded_1(const char *pathname,
|
||||
const char *exclude = x->pattern;
|
||||
int to_exclude = x->to_exclude;
|
||||
|
||||
if (x->flags & EXC_FLAG_MUSTBEDIR) {
|
||||
if (*dtype == DT_UNKNOWN)
|
||||
*dtype = get_dtype(NULL, pathname);
|
||||
if (*dtype != DT_DIR)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (x->flags & EXC_FLAG_NODIR) {
|
||||
/* match basename */
|
||||
if (x->flags & EXC_FLAG_NOWILDCARD) {
|
||||
@@ -314,7 +338,7 @@ static int excluded_1(const char *pathname,
|
||||
return -1; /* undecided */
|
||||
}
|
||||
|
||||
int excluded(struct dir_struct *dir, const char *pathname)
|
||||
int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
|
||||
{
|
||||
int pathlen = strlen(pathname);
|
||||
int st;
|
||||
@@ -323,7 +347,8 @@ int excluded(struct dir_struct *dir, const char *pathname)
|
||||
|
||||
prep_exclude(dir, pathname, basename-pathname);
|
||||
for (st = EXC_CMDL; st <= EXC_FILE; st++) {
|
||||
switch (excluded_1(pathname, pathlen, basename, &dir->exclude_list[st])) {
|
||||
switch (excluded_1(pathname, pathlen, basename,
|
||||
dtype_p, &dir->exclude_list[st])) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
@@ -346,7 +371,7 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)
|
||||
|
||||
struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
|
||||
{
|
||||
if (cache_name_pos(pathname, len) >= 0)
|
||||
if (cache_name_exists(pathname, len))
|
||||
return NULL;
|
||||
|
||||
ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
|
||||
@@ -391,7 +416,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
|
||||
break;
|
||||
if (endchar == '/')
|
||||
return index_directory;
|
||||
if (!endchar && S_ISGITLINK(ntohl(ce->ce_mode)))
|
||||
if (!endchar && S_ISGITLINK(ce->ce_mode))
|
||||
return index_gitdir;
|
||||
}
|
||||
return index_nonexistent;
|
||||
@@ -508,7 +533,7 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
|
||||
|
||||
static int get_dtype(struct dirent *de, const char *path)
|
||||
{
|
||||
int dtype = DTYPE(de);
|
||||
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
|
||||
struct stat st;
|
||||
|
||||
if (dtype != DT_UNKNOWN)
|
||||
@@ -560,7 +585,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
|
||||
if (simplify_away(fullname, baselen + len, simplify))
|
||||
continue;
|
||||
|
||||
exclude = excluded(dir, fullname);
|
||||
dtype = DTYPE(de);
|
||||
exclude = excluded(dir, fullname, &dtype);
|
||||
if (exclude && dir->collect_ignored
|
||||
&& in_pathspec(fullname, baselen + len, simplify))
|
||||
dir_add_ignored(dir, fullname, baselen + len);
|
||||
@@ -572,7 +598,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
|
||||
if (exclude && !dir->show_ignored)
|
||||
continue;
|
||||
|
||||
dtype = get_dtype(de, fullname);
|
||||
if (dtype == DT_UNKNOWN)
|
||||
dtype = get_dtype(de, fullname);
|
||||
|
||||
/*
|
||||
* Do we want to see just the ignored files?
|
||||
|
||||
3
dir.h
3
dir.h
@@ -9,6 +9,7 @@ struct dir_entry {
|
||||
#define EXC_FLAG_NODIR 1
|
||||
#define EXC_FLAG_NOWILDCARD 2
|
||||
#define EXC_FLAG_ENDSWITH 4
|
||||
#define EXC_FLAG_MUSTBEDIR 8
|
||||
|
||||
struct exclude_list {
|
||||
int nr;
|
||||
@@ -67,7 +68,7 @@ extern int match_pathspec(const char **pathspec, const char *name, int namelen,
|
||||
|
||||
extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
|
||||
|
||||
extern int excluded(struct dir_struct *, const char *);
|
||||
extern int excluded(struct dir_struct *, const char *, int *);
|
||||
extern void add_excludes_from_file(struct dir_struct *, const char *fname);
|
||||
extern void add_exclude(const char *string, const char *base,
|
||||
int baselen, struct exclude_list *which);
|
||||
|
||||
6
entry.c
6
entry.c
@@ -103,7 +103,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
|
||||
int fd;
|
||||
long wrote;
|
||||
|
||||
switch (ntohl(ce->ce_mode) & S_IFMT) {
|
||||
switch (ce->ce_mode & S_IFMT) {
|
||||
char *new;
|
||||
struct strbuf buf;
|
||||
unsigned long size;
|
||||
@@ -129,7 +129,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
|
||||
strcpy(path, ".merge_file_XXXXXX");
|
||||
fd = mkstemp(path);
|
||||
} else
|
||||
fd = create_file(path, ntohl(ce->ce_mode));
|
||||
fd = create_file(path, ce->ce_mode);
|
||||
if (fd < 0) {
|
||||
free(new);
|
||||
return error("git-checkout-index: unable to create file %s (%s)",
|
||||
@@ -221,7 +221,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
|
||||
unlink(path);
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* If it is a gitlink, leave it alone! */
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode)))
|
||||
if (S_ISGITLINK(ce->ce_mode))
|
||||
return 0;
|
||||
if (!state->force)
|
||||
return error("%s is a directory", path);
|
||||
|
||||
@@ -30,11 +30,12 @@ int core_compression_seen;
|
||||
size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
|
||||
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
|
||||
size_t delta_base_cache_limit = 16 * 1024 * 1024;
|
||||
char *pager_program;
|
||||
const char *pager_program;
|
||||
int pager_use_color = 1;
|
||||
char *editor_program;
|
||||
char *excludes_file;
|
||||
const char *editor_program;
|
||||
const char *excludes_file;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
|
||||
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
|
||||
|
||||
/* This is set by setup_git_dir_gently() and/or git_default_config() */
|
||||
|
||||
@@ -372,6 +372,8 @@ static void write_branch_report(FILE *rpt, struct branch *b)
|
||||
fputc('\n', rpt);
|
||||
}
|
||||
|
||||
static void dump_marks_helper(FILE *, uintmax_t, struct mark_set *);
|
||||
|
||||
static void write_crash_report(const char *err)
|
||||
{
|
||||
char *loc = git_path("fast_import_crash_%d", getpid());
|
||||
@@ -430,12 +432,37 @@ static void write_crash_report(const char *err)
|
||||
write_branch_report(rpt, b);
|
||||
}
|
||||
|
||||
if (first_tag) {
|
||||
struct tag *tg;
|
||||
fputc('\n', rpt);
|
||||
fputs("Annotated Tags\n", rpt);
|
||||
fputs("--------------\n", rpt);
|
||||
for (tg = first_tag; tg; tg = tg->next_tag) {
|
||||
fputs(sha1_to_hex(tg->sha1), rpt);
|
||||
fputc(' ', rpt);
|
||||
fputs(tg->name, rpt);
|
||||
fputc('\n', rpt);
|
||||
}
|
||||
}
|
||||
|
||||
fputc('\n', rpt);
|
||||
fputs("Marks\n", rpt);
|
||||
fputs("-----\n", rpt);
|
||||
if (mark_file)
|
||||
fprintf(rpt, " exported to %s\n", mark_file);
|
||||
else
|
||||
dump_marks_helper(rpt, 0, marks);
|
||||
|
||||
fputc('\n', rpt);
|
||||
fputs("-------------------\n", rpt);
|
||||
fputs("END OF CRASH REPORT\n", rpt);
|
||||
fclose(rpt);
|
||||
}
|
||||
|
||||
static void end_packfile(void);
|
||||
static void unkeep_all_packs(void);
|
||||
static void dump_marks(void);
|
||||
|
||||
static NORETURN void die_nicely(const char *err, va_list params)
|
||||
{
|
||||
static int zombie;
|
||||
@@ -449,6 +476,9 @@ static NORETURN void die_nicely(const char *err, va_list params)
|
||||
if (!zombie) {
|
||||
zombie = 1;
|
||||
write_crash_report(message);
|
||||
end_packfile();
|
||||
unkeep_all_packs();
|
||||
dump_marks();
|
||||
}
|
||||
exit(128);
|
||||
}
|
||||
@@ -1204,6 +1234,8 @@ static void load_tree(struct tree_entry *root)
|
||||
die("Not a tree: %s", sha1_to_hex(sha1));
|
||||
t->delta_depth = myoe->depth;
|
||||
buf = gfi_unpack_entry(myoe, &size);
|
||||
if (!buf)
|
||||
die("Can't load tree %s", sha1_to_hex(sha1));
|
||||
} else {
|
||||
enum object_type type;
|
||||
buf = read_sha1_file(sha1, &type, &size);
|
||||
|
||||
@@ -16,6 +16,8 @@ struct fetch_pack_args
|
||||
};
|
||||
|
||||
struct ref *fetch_pack(struct fetch_pack_args *args,
|
||||
int fd[], struct child_process *conn,
|
||||
const struct ref *ref,
|
||||
const char *dest,
|
||||
int nr_heads,
|
||||
char **heads,
|
||||
|
||||
@@ -14,7 +14,7 @@ b,binary pass --allo-binary-replacement to git-apply
|
||||
3,3way allow fall back on 3way merging if needed
|
||||
s,signoff add a Signed-off-by line to the commit message
|
||||
u,utf8 recode into utf8 (default)
|
||||
k,keep pass -k flagg to git-mailinfo
|
||||
k,keep pass -k flag to git-mailinfo
|
||||
whitespace= pass it through git-apply
|
||||
C= pass it through git-apply
|
||||
p= pass it through git-apply
|
||||
|
||||
@@ -26,6 +26,9 @@ OPTIONS_SPEC=
|
||||
. git-sh-setup
|
||||
require_work_tree
|
||||
|
||||
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
||||
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
|
||||
|
||||
sq() {
|
||||
@@PERL@@ -e '
|
||||
for (@ARGV) {
|
||||
@@ -60,7 +63,8 @@ bisect_start() {
|
||||
# top-of-line master first!
|
||||
#
|
||||
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) ||
|
||||
die "Bad HEAD - I need a symbolic ref"
|
||||
head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
|
||||
die "Bad HEAD - I need a HEAD"
|
||||
case "$head" in
|
||||
refs/heads/bisect)
|
||||
if [ -s "$GIT_DIR/head-name" ]; then
|
||||
@@ -70,7 +74,7 @@ bisect_start() {
|
||||
fi
|
||||
git checkout $branch || exit
|
||||
;;
|
||||
refs/heads/*)
|
||||
refs/heads/*|$_x40)
|
||||
[ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
|
||||
echo "${head#refs/heads/}" >"$GIT_DIR/head-name"
|
||||
;;
|
||||
@@ -131,7 +135,7 @@ bisect_write() {
|
||||
*) die "Bad bisect_write argument: $state" ;;
|
||||
esac
|
||||
git update-ref "refs/bisect/$tag" "$rev"
|
||||
echo "# $state: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
|
||||
echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
|
||||
test -z "$nolog" && echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
|
||||
}
|
||||
|
||||
|
||||
@@ -440,6 +440,12 @@ static inline int strtol_i(char const *s, int base, int *result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef INTERNAL_QSORT
|
||||
void git_qsort(void *base, size_t nmemb, size_t size,
|
||||
int(*compar)(const void *, const void *));
|
||||
#define qsort git_qsort
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
@@ -5,6 +5,7 @@ use Getopt::Std;
|
||||
use File::Temp qw(tempdir);
|
||||
use Data::Dumper;
|
||||
use File::Basename qw(basename dirname);
|
||||
use File::Spec;
|
||||
|
||||
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w);
|
||||
|
||||
@@ -15,17 +16,15 @@ $opt_h && usage();
|
||||
die "Need at least one commit identifier!" unless @ARGV;
|
||||
|
||||
if ($opt_w) {
|
||||
# Remember where GIT_DIR is before changing to CVS checkout
|
||||
unless ($ENV{GIT_DIR}) {
|
||||
# Remember where our GIT_DIR is before changing to CVS checkout
|
||||
# No GIT_DIR set. Figure it out for ourselves
|
||||
my $gd =`git-rev-parse --git-dir`;
|
||||
chomp($gd);
|
||||
if ($gd eq '.git') {
|
||||
my $wd = `pwd`;
|
||||
chomp($wd);
|
||||
$gd = $wd."/.git" ;
|
||||
}
|
||||
$ENV{GIT_DIR} = $gd;
|
||||
}
|
||||
# Make sure GIT_DIR is absolute
|
||||
$ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
|
||||
|
||||
if (! -d $opt_w."/CVS" ) {
|
||||
die "$opt_w is not a CVS checkout";
|
||||
|
||||
@@ -164,7 +164,7 @@ if ($#ARGV == 0) {
|
||||
|
||||
our @mergerx = ();
|
||||
if ($opt_m) {
|
||||
@mergerx = ( qr/\W(?:from|of|merge|merging|merged) (\w+)/i );
|
||||
@mergerx = ( qr/\b(?:from|of|merge|merging|merged) (\w+)/i );
|
||||
}
|
||||
if ($opt_M) {
|
||||
push (@mergerx, qr/$opt_M/);
|
||||
|
||||
@@ -276,10 +276,11 @@ while read commit parents; do
|
||||
eval "$filter_tree" < /dev/null ||
|
||||
die "tree filter failed: $filter_tree"
|
||||
|
||||
git diff-index -r $commit | cut -f 2- | tr '\012' '\000' | \
|
||||
xargs -0 git update-index --add --replace --remove
|
||||
git ls-files -z --others | \
|
||||
xargs -0 git update-index --add --replace --remove
|
||||
(
|
||||
git diff-index -r --name-only $commit
|
||||
git ls-files --others
|
||||
) |
|
||||
git update-index --add --replace --remove --stdin
|
||||
fi
|
||||
|
||||
eval "$filter_index" < /dev/null ||
|
||||
|
||||
@@ -13,6 +13,7 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
|
||||
uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
|
||||
|
||||
SCRIPT_SH = git-gui.sh
|
||||
GITGUI_MAIN := git-gui
|
||||
@@ -93,7 +94,14 @@ endif
|
||||
|
||||
TCL_PATH ?= tclsh
|
||||
TCLTK_PATH ?= wish
|
||||
TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app
|
||||
|
||||
ifeq ($(uname_S),Darwin)
|
||||
TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app
|
||||
ifeq ($(shell expr "$(uname_R)" : '9\.'),2)
|
||||
TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app
|
||||
endif
|
||||
TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app)
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(MAKEFLAGS),s),s)
|
||||
QUIET_GEN =
|
||||
@@ -147,7 +155,7 @@ git-gui: GIT-VERSION-FILE GIT-GUI-VARS
|
||||
echo then >>$@+ && \
|
||||
echo ' 'echo \'git-gui version '$(GITGUI_VERSION)'\' >>$@+ && \
|
||||
echo else >>$@+ && \
|
||||
echo ' 'exec \''$(libdir_SQ)/Git Gui.app/Contents/MacOS/Wish'\' \
|
||||
echo ' 'exec \''$(libdir_SQ)/Git Gui.app/Contents/MacOS/$(subst \,,$(TKEXECUTABLE))'\' \
|
||||
'"$$0" "$$@"' >>$@+ && \
|
||||
echo fi >>$@+ && \
|
||||
chmod +x $@+ && \
|
||||
@@ -157,14 +165,15 @@ Git\ Gui.app: GIT-VERSION-FILE GIT-GUI-VARS \
|
||||
macosx/Info.plist \
|
||||
macosx/git-gui.icns \
|
||||
macosx/AppMain.tcl \
|
||||
$(TKFRAMEWORK)/Contents/MacOS/Wish
|
||||
$(TKFRAMEWORK)/Contents/MacOS/$(TKEXECUTABLE)
|
||||
$(QUIET_GEN)rm -rf '$@' '$@'+ && \
|
||||
mkdir -p '$@'+/Contents/MacOS && \
|
||||
mkdir -p '$@'+/Contents/Resources/Scripts && \
|
||||
cp '$(subst ','\'',$(TKFRAMEWORK))/Contents/MacOS/Wish' \
|
||||
cp '$(subst ','\'',$(subst \,,$(TKFRAMEWORK)/Contents/MacOS/$(TKEXECUTABLE)))' \
|
||||
'$@'+/Contents/MacOS && \
|
||||
cp macosx/git-gui.icns '$@'+/Contents/Resources && \
|
||||
sed -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
|
||||
-e 's/@@GITGUI_TKEXECUTABLE@@/$(TKEXECUTABLE)/g' \
|
||||
macosx/Info.plist \
|
||||
>'$@'+/Contents/Info.plist && \
|
||||
sed -e 's|@@gitexecdir@@|$(gitexecdir_SQ)|' \
|
||||
|
||||
@@ -612,6 +612,7 @@ set default_config(gui.pruneduringfetch) false
|
||||
set default_config(gui.trustmtime) false
|
||||
set default_config(gui.diffcontext) 5
|
||||
set default_config(gui.newbranchtemplate) {}
|
||||
set default_config(gui.spellingdictionary) {}
|
||||
set default_config(gui.fontui) [font configure font_ui]
|
||||
set default_config(gui.fontdiff) [font configure font_diff]
|
||||
set font_descs {
|
||||
@@ -1683,6 +1684,7 @@ set is_quitting 0
|
||||
proc do_quit {} {
|
||||
global ui_comm is_quitting repo_config commit_type
|
||||
global GITGUI_BCK_exists GITGUI_BCK_i
|
||||
global ui_comm_spell
|
||||
|
||||
if {$is_quitting} return
|
||||
set is_quitting 1
|
||||
@@ -1710,6 +1712,12 @@ proc do_quit {} {
|
||||
}
|
||||
}
|
||||
|
||||
# -- Cancel our spellchecker if its running.
|
||||
#
|
||||
if {[info exists ui_comm_spell]} {
|
||||
$ui_comm_spell stop
|
||||
}
|
||||
|
||||
# -- Remove our editor backup, its not needed.
|
||||
#
|
||||
after cancel $GITGUI_BCK_i
|
||||
@@ -2454,7 +2462,7 @@ $ctxm add separator
|
||||
$ctxm add command \
|
||||
-label [mc "Sign Off"] \
|
||||
-command do_signoff
|
||||
bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
|
||||
set ui_comm_ctxm $ctxm
|
||||
|
||||
# -- Diff Header
|
||||
#
|
||||
@@ -2857,6 +2865,30 @@ if {[winfo exists $ui_comm]} {
|
||||
}
|
||||
|
||||
backup_commit_buffer
|
||||
|
||||
# -- If the user has aspell available we can drive it
|
||||
# in pipe mode to spellcheck the commit message.
|
||||
#
|
||||
set spell_cmd [list |]
|
||||
set spell_dict [get_config gui.spellingdictionary]
|
||||
lappend spell_cmd aspell
|
||||
if {$spell_dict ne {}} {
|
||||
lappend spell_cmd --master=$spell_dict
|
||||
}
|
||||
lappend spell_cmd --mode=none
|
||||
lappend spell_cmd --encoding=utf-8
|
||||
lappend spell_cmd pipe
|
||||
if {$spell_dict eq {none}
|
||||
|| [catch {set spell_fd [open $spell_cmd r+]} spell_err]} {
|
||||
bind_button3 $ui_comm [list tk_popup $ui_comm_ctxm %X %Y]
|
||||
} else {
|
||||
set ui_comm_spell [spellcheck::init \
|
||||
$spell_fd \
|
||||
$ui_comm \
|
||||
$ui_comm_ctxm \
|
||||
]
|
||||
}
|
||||
unset -nocomplain spell_cmd spell_fd spell_err spell_dict
|
||||
}
|
||||
|
||||
lock_index begin-read
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
proc do_about {} {
|
||||
global appvers copyright oguilib
|
||||
global tcl_patchLevel tk_patchLevel
|
||||
global ui_comm_spell
|
||||
|
||||
set w .about_dialog
|
||||
toplevel $w
|
||||
@@ -40,6 +41,10 @@ proc do_about {} {
|
||||
append v "Tcl version $tcl_patchLevel"
|
||||
append v ", Tk version $tk_patchLevel"
|
||||
}
|
||||
if {[info exists ui_comm_spell]} {
|
||||
append v "\n"
|
||||
append v [$ui_comm_spell version]
|
||||
}
|
||||
|
||||
set d {}
|
||||
append d "git wrapper: $::_git\n"
|
||||
|
||||
@@ -280,7 +280,7 @@ The rescan will be automatically started now.
|
||||
} elseif {[is_config_true gui.trustmtime]} {
|
||||
_readtree $this
|
||||
} else {
|
||||
ui_status {Refreshing file status...}
|
||||
ui_status [mc "Refreshing file status..."]
|
||||
set fd [git_read update-index \
|
||||
-q \
|
||||
--unmerged \
|
||||
@@ -320,7 +320,7 @@ method _readtree {} {
|
||||
set readtree_d {}
|
||||
$::main_status start \
|
||||
[mc "Updating working directory to '%s'..." [_name $this]] \
|
||||
{files checked out}
|
||||
[mc "files checked out"]
|
||||
|
||||
set fd [git_read --stderr read-tree \
|
||||
-m \
|
||||
@@ -447,7 +447,7 @@ If you wanted to be on a branch, create one now starting from 'This Detached Che
|
||||
} else {
|
||||
repository_state commit_type HEAD MERGE_HEAD
|
||||
set PARENT $HEAD
|
||||
ui_status "Checked out '$name'."
|
||||
ui_status [mc "Checked out '%s'." $name]
|
||||
}
|
||||
delete_this
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ A good commit message has the following format:
|
||||
return
|
||||
}
|
||||
|
||||
ui_status {Calling pre-commit hook...}
|
||||
ui_status [mc "Calling pre-commit hook..."]
|
||||
set pch_error {}
|
||||
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
|
||||
fileevent $fd_ph readable \
|
||||
@@ -233,7 +233,7 @@ proc commit_prehook_wait {fd_ph curHEAD msg_p} {
|
||||
if {[eof $fd_ph]} {
|
||||
if {[catch {close $fd_ph}]} {
|
||||
catch {file delete $msg_p}
|
||||
ui_status {Commit declined by pre-commit hook.}
|
||||
ui_status [mc "Commit declined by pre-commit hook."]
|
||||
hook_failed_popup pre-commit $pch_error
|
||||
unlock_index
|
||||
} else {
|
||||
@@ -256,7 +256,7 @@ proc commit_commitmsg {curHEAD msg_p} {
|
||||
return
|
||||
}
|
||||
|
||||
ui_status {Calling commit-msg hook...}
|
||||
ui_status [mc "Calling commit-msg hook..."]
|
||||
set pch_error {}
|
||||
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
|
||||
fileevent $fd_ph readable \
|
||||
@@ -271,7 +271,7 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
|
||||
if {[eof $fd_ph]} {
|
||||
if {[catch {close $fd_ph}]} {
|
||||
catch {file delete $msg_p}
|
||||
ui_status {Commit declined by commit-msg hook.}
|
||||
ui_status [mc "Commit declined by commit-msg hook."]
|
||||
hook_failed_popup commit-msg $pch_error
|
||||
unlock_index
|
||||
} else {
|
||||
@@ -284,7 +284,7 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
|
||||
}
|
||||
|
||||
proc commit_writetree {curHEAD msg_p} {
|
||||
ui_status {Committing changes...}
|
||||
ui_status [mc "Committing changes..."]
|
||||
set fd_wt [git_read write-tree]
|
||||
fileevent $fd_wt readable \
|
||||
[list commit_committree $fd_wt $curHEAD $msg_p]
|
||||
@@ -301,7 +301,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {
|
||||
if {[catch {close $fd_wt} err]} {
|
||||
catch {file delete $msg_p}
|
||||
error_popup [strcat [mc "write-tree failed:"] "\n\n$err"]
|
||||
ui_status {Commit failed.}
|
||||
ui_status [mc "Commit failed."]
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
@@ -345,7 +345,7 @@ A rescan will be automatically started now.
|
||||
if {[catch {set cmt_id [eval git $cmd]} err]} {
|
||||
catch {file delete $msg_p}
|
||||
error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"]
|
||||
ui_status {Commit failed.}
|
||||
ui_status [mc "Commit failed."]
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
@@ -365,7 +365,7 @@ A rescan will be automatically started now.
|
||||
} err]} {
|
||||
catch {file delete $msg_p}
|
||||
error_popup [strcat [mc "update-ref failed:"] "\n\n$err"]
|
||||
ui_status {Commit failed.}
|
||||
ui_status [mc "Commit failed."]
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ proc add_helper {txt paths} {
|
||||
update_index \
|
||||
$txt \
|
||||
$pathList \
|
||||
[concat $after {ui_status {Ready to commit.}}]
|
||||
[concat $after {ui_status [mc "Ready to commit."]}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user