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:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -148,6 +148,7 @@ git-write-tree
|
||||
git-core-*/?*
|
||||
gitk-wish
|
||||
gitweb/gitweb.cgi
|
||||
test-absolute-path
|
||||
test-chmtime
|
||||
test-date
|
||||
test-delta
|
||||
|
||||
@@ -44,6 +44,11 @@ INSTALL?=install
|
||||
RM ?= rm -f
|
||||
DOC_REF = origin/man
|
||||
|
||||
infodir?=$(prefix)/share/info
|
||||
MAKEINFO=makeinfo
|
||||
INSTALL_INFO=install-info
|
||||
DOCBOOK2X_TEXI=docbook2x-texi
|
||||
|
||||
-include ../config.mak.autogen
|
||||
-include ../config.mak
|
||||
|
||||
@@ -67,6 +72,8 @@ man1: $(DOC_MAN1)
|
||||
man5: $(DOC_MAN5)
|
||||
man7: $(DOC_MAN7)
|
||||
|
||||
info: git.info
|
||||
|
||||
install: man
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(man5dir)
|
||||
@@ -75,6 +82,14 @@ install: man
|
||||
$(INSTALL) -m644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
|
||||
$(INSTALL) -m644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
|
||||
install-info: info
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(infodir)
|
||||
$(INSTALL) -m644 git.info $(DESTDIR)$(infodir)
|
||||
if test -r $(DESTDIR)$(infodir)/dir; then \
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) git.info ;\
|
||||
else \
|
||||
echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
|
||||
fi
|
||||
|
||||
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
$(MAKE) -C ../ GIT-VERSION-FILE
|
||||
@@ -104,13 +119,14 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
|
||||
$(cmds_txt): cmd-list.made
|
||||
|
||||
cmd-list.made: cmd-list.perl $(MAN1_TXT)
|
||||
$(RM) $@
|
||||
perl ./cmd-list.perl
|
||||
date >$@
|
||||
|
||||
git.7 git.html: git.txt core-intro.txt
|
||||
|
||||
clean:
|
||||
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 howto-index.txt howto/*.html doc.dep
|
||||
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 *.texi *.texi+ howto-index.txt howto/*.html doc.dep
|
||||
$(RM) $(cmds_txt) *.made
|
||||
|
||||
%.html : %.txt
|
||||
@@ -138,6 +154,13 @@ XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
|
||||
user-manual.html: user-manual.xml
|
||||
xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
|
||||
|
||||
git.info: user-manual.xml
|
||||
$(RM) $@ $*.texi $*.texi+
|
||||
$(DOCBOOK2X_TEXI) user-manual.xml --to-stdout >$*.texi+
|
||||
perl fix-texi.perl <$*.texi+ >$*.texi
|
||||
$(MAKEINFO) --no-split $*.texi
|
||||
$(RM) $*.texi $*.texi+
|
||||
|
||||
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||
$(RM) $@+ $@
|
||||
sh ./howto-index.sh $(wildcard howto/*.txt) >$@+
|
||||
|
||||
30
Documentation/RelNotes-1.5.2.5.txt
Normal file
30
Documentation/RelNotes-1.5.2.5.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
GIT v1.5.2.5 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.2.4
|
||||
--------------------
|
||||
|
||||
* Bugfixes
|
||||
|
||||
- "git add -u" had a serious data corruption problem in one
|
||||
special case (when the changes to a subdirectory's files
|
||||
consist only deletion of files).
|
||||
|
||||
- "git add -u <path>" did not work from a subdirectory.
|
||||
|
||||
- "git apply" left an empty directory after all its files are
|
||||
renamed away.
|
||||
|
||||
- "git $anycmd foo/bar", when there is a file 'foo' in the
|
||||
working tree, complained that "git $anycmd foo/bar --" form
|
||||
should be used to disambiguate between revs and files,
|
||||
which was completely bogus.
|
||||
|
||||
- "git checkout-index" and other commands that checks out
|
||||
files to the work tree tried unlink(2) on directories,
|
||||
which is a sane thing to do on sane systems, but not on
|
||||
Solaris when you are root.
|
||||
|
||||
* Documentation Fixes and Updates
|
||||
|
||||
- A handful documentation fixes.
|
||||
@@ -9,6 +9,19 @@ Updates since v1.5.2
|
||||
|
||||
* The submodule support has Porcelain layer.
|
||||
|
||||
Note that the current submodule support is minimal and this is
|
||||
deliberately so. A design decision we made is that operations
|
||||
at the supermodule level do not recurse into submodules by
|
||||
default. The expectation is that later we would add a
|
||||
mechanism to tell git which submodules the user is interested
|
||||
in, and this information might be used to determine the
|
||||
recursive behaviour of certain commands (e.g. "git checkout"
|
||||
and "git diff"), but currently we haven't agreed on what that
|
||||
mechanism should look like. Therefore, if you use submodules,
|
||||
you would probably need "git submodule update" on the
|
||||
submodules you care about after running a "git checkout" at
|
||||
the supermodule level.
|
||||
|
||||
* There are a handful pack-objects changes to help you cope better
|
||||
with repositories with pathologically large blobs in them.
|
||||
|
||||
@@ -46,21 +59,21 @@ Updates since v1.5.2
|
||||
- "git log" learned a new option "--follow", to follow
|
||||
renaming history of a single file.
|
||||
|
||||
- "git-filter-branch" lets you rewrite the revision history of
|
||||
- "git filter-branch" lets you rewrite the revision history of
|
||||
specified branches. You can specify a number of filters to
|
||||
modify the commits, files and trees.
|
||||
|
||||
- "git-cvsserver" learned new options (--base-path, --export-all,
|
||||
--strict-paths) inspired by git-daemon.
|
||||
- "git cvsserver" learned new options (--base-path, --export-all,
|
||||
--strict-paths) inspired by "git daemon".
|
||||
|
||||
- "git daemon --base-path-relaxed" can help migrating a repository URL
|
||||
that did not use to use --base-path to use --base-path.
|
||||
|
||||
- "git-commit" can use "-t templatefile" option and commit.template
|
||||
- "git commit" can use "-t templatefile" option and commit.template
|
||||
configuration variable to prime the commit message given to you in the
|
||||
editor.
|
||||
|
||||
- "git-submodule" command helps you manage the projects from
|
||||
- "git submodule" command helps you manage the projects from
|
||||
the superproject that contain them.
|
||||
|
||||
- In addition to core.compression configuration option,
|
||||
@@ -68,15 +81,15 @@ Updates since v1.5.2
|
||||
independently tweak zlib compression levels used for loose
|
||||
and packed objects.
|
||||
|
||||
- "git-ls-tree -l" shows size of blobs pointed at by the
|
||||
- "git ls-tree -l" shows size of blobs pointed at by the
|
||||
tree entries, similar to "/bin/ls -l".
|
||||
|
||||
- "git-rev-list" learned --regexp-ignore-case and
|
||||
- "git rev-list" learned --regexp-ignore-case and
|
||||
--extended-regexp options to tweak its matching logic used
|
||||
for --grep fitering.
|
||||
|
||||
- "git-describe --contains" is a handier way to call more
|
||||
obscure command "git-name-rev --tags".
|
||||
- "git describe --contains" is a handier way to call more
|
||||
obscure command "git name-rev --tags".
|
||||
|
||||
- "git gc --aggressive" tells the command to spend more cycles
|
||||
to optimize the repository harder.
|
||||
@@ -112,6 +125,9 @@ Updates since v1.5.2
|
||||
- "git config" learned NUL terminated output format via -z to
|
||||
help scripts.
|
||||
|
||||
- "git add" learned "--refresh <paths>..." option to selectively refresh
|
||||
the cached stat information.
|
||||
|
||||
- "git init -q" makes the command quieter.
|
||||
|
||||
* Updated behavior of existing commands.
|
||||
@@ -126,9 +142,19 @@ Updates since v1.5.2
|
||||
of the format ('tgz', 'tbz2' or 'zip'). Please update the
|
||||
your configuration file accordingly.
|
||||
|
||||
- "git clone" uses -l (hardlink files under .git) by default when
|
||||
cloning locally.
|
||||
|
||||
- "git bundle create" can now create a bundle without negative refs,
|
||||
i.e. "everything since the beginning up to certain points".
|
||||
|
||||
- "git diff" (but not the plumbing level "git diff-tree") now
|
||||
recursively descends into trees by default.
|
||||
|
||||
- "git diff" does not show differences that come only from
|
||||
stat-dirtiness in the form of "diff --git" header anymore. When
|
||||
generating a textual diff, it shows a warning message at the end.
|
||||
|
||||
- The editor to use with many interactive commands can be
|
||||
overridden with GIT_EDITOR environment variable, or if it
|
||||
does not exist, with core.editor configuration variable. As
|
||||
@@ -143,8 +169,16 @@ Updates since v1.5.2
|
||||
given strings now have shorter abbreviations. -i is for ignore case,
|
||||
and -E is for extended regexp.
|
||||
|
||||
- "git log" learned --log-size to show the number of bytes in
|
||||
the log message part of the output to help qgit.
|
||||
|
||||
- "git svn dcommit" retains local merge information.
|
||||
|
||||
- "git svnimport" allows an empty string to be specified as the
|
||||
trunk/ directory. This is necessary to suck data from a SVN
|
||||
repository that doe not have trunk/ branches/ and tags/ organization
|
||||
at all.
|
||||
|
||||
- "git config" to set values also honors type flags like --bool
|
||||
and --int.
|
||||
|
||||
@@ -167,7 +201,7 @@ Updates since v1.5.2
|
||||
and the handcrafted ones the old code created was not
|
||||
properly formed anyway.
|
||||
|
||||
- "git-push" pretends that you immediately fetched back from
|
||||
- "git push" pretends that you immediately fetched back from
|
||||
the remote by updating corresponding remote tracking
|
||||
branches if you have any.
|
||||
|
||||
@@ -177,10 +211,10 @@ Updates since v1.5.2
|
||||
- "git commit --amend" is now compatible with various message source
|
||||
options such as -m/-C/-c/-F.
|
||||
|
||||
- "git-apply --whitespace=strip" removes blank lines added at
|
||||
- "git apply --whitespace=strip" removes blank lines added at
|
||||
the end of the file.
|
||||
|
||||
- "git-fetch" over git native protocols with "-v" option shows
|
||||
- "git fetch" over git native protocols with "-v" option shows
|
||||
connection status, and the IP address of the other end, to
|
||||
help diagnosing problems.
|
||||
|
||||
@@ -195,10 +229,10 @@ Updates since v1.5.2
|
||||
- "--find-copies-harder" option to diff family can now be
|
||||
spelled as "-C -C" for brevity.
|
||||
|
||||
- "git-mailsplit" (hence "git-am") can read from Maildir
|
||||
- "git mailsplit" (hence "git am") can read from Maildir
|
||||
formatted mailboxes.
|
||||
|
||||
- "git-cvsserver" does not barf upon seeing "cvs login"
|
||||
- "git cvsserver" does not barf upon seeing "cvs login"
|
||||
request.
|
||||
|
||||
- "pack-objects" honors "delta" attribute set in
|
||||
@@ -208,7 +242,7 @@ Updates since v1.5.2
|
||||
- "new-workdir" script (in contrib) can now be used with a
|
||||
bare repository.
|
||||
|
||||
- "git-mergetool" learned to use gvimdiff.
|
||||
- "git mergetool" learned to use gvimdiff.
|
||||
|
||||
- "gitview" (in contrib) has a better blame interface.
|
||||
|
||||
@@ -223,8 +257,8 @@ Updates since v1.5.2
|
||||
"oneline".
|
||||
|
||||
- "git p4import" has been demoted to contrib status. For
|
||||
a superior option, checkout the git-p4 front end to
|
||||
git-fast-import (also in contrib). The man page and p4
|
||||
a superior option, checkout the "git p4" front end to
|
||||
"git fast-import" (also in contrib). The man page and p4
|
||||
rpm have been removed as well.
|
||||
|
||||
- "git mailinfo" (hence "am") now tries to see if the message
|
||||
@@ -237,13 +271,15 @@ Updates since v1.5.2
|
||||
without parameter defined with "func()", not "func(void)")
|
||||
have been eradicated.
|
||||
|
||||
- "git tag" and "git verify-tag" have been rewritten in C.
|
||||
|
||||
* Performance Tweaks
|
||||
|
||||
- git-pack-objects avoids re-deltification cost by caching
|
||||
- "git pack-objects" avoids re-deltification cost by caching
|
||||
small enough delta results it creates while looking for the
|
||||
best delta candidates.
|
||||
|
||||
- git-pack-objects learned a new heuristcs to prefer delta
|
||||
- "git pack-objects" learned a new heuristcs to prefer delta
|
||||
that is shallower in depth over the smallest delta
|
||||
possible. This improves both overall packfile access
|
||||
performance and packfile density.
|
||||
@@ -260,6 +296,13 @@ Updates since v1.5.2
|
||||
- verifying pack contents done by "git fsck --full" got boost
|
||||
by carefully choosing the order to verify objects in them.
|
||||
|
||||
- "git read-tree -m" to read into an already populated index
|
||||
has been optimized vastly. The effect of this can be seen
|
||||
when switching branches that have differences in only a
|
||||
handful paths.
|
||||
|
||||
- "git commit paths..." has also been optimized.
|
||||
|
||||
|
||||
Fixes since v1.5.2
|
||||
------------------
|
||||
|
||||
@@ -64,11 +64,11 @@ of lines before or after the line given by <start>.
|
||||
assigns blame to the lines that were moved down (i.e. A)
|
||||
to the child commit. With this option, both groups of lines
|
||||
are blamed on the parent.
|
||||
|
||||
<num> is optional but it is the lower bound on the number of
|
||||
alphanumeric characters that git must detect as moving
|
||||
within a file for it to associate those lines with the parent
|
||||
commit.
|
||||
+
|
||||
<num> is optional but it is the lower bound on the number of
|
||||
alphanumeric characters that git must detect as moving
|
||||
within a file for it to associate those lines with the parent
|
||||
commit.
|
||||
|
||||
-C|<num>|::
|
||||
In addition to `-M`, detect lines copied from other
|
||||
@@ -77,11 +77,11 @@ of lines before or after the line given by <start>.
|
||||
around across files. When this option is given twice,
|
||||
the command looks for copies from all other files in the
|
||||
parent for the commit that creates the file in addition.
|
||||
|
||||
<num> is optional but it is the lower bound on the number of
|
||||
alphanumeric characters that git must detect as moving
|
||||
between files for it to associate those lines with the parent
|
||||
commit.
|
||||
+
|
||||
<num> is optional but it is the lower bound on the number of
|
||||
alphanumeric characters that git must detect as moving
|
||||
between files for it to associate those lines with the parent
|
||||
commit.
|
||||
|
||||
-h, --help::
|
||||
Show help message.
|
||||
|
||||
@@ -68,6 +68,8 @@ for my $cat (qw(ancillaryinterrogators
|
||||
}
|
||||
}
|
||||
|
||||
# The following list is sorted with "sort -d" to make it easier
|
||||
# to find entry in the resulting git.html manual page.
|
||||
__DATA__
|
||||
git-add mainporcelain
|
||||
git-am mainporcelain
|
||||
@@ -80,9 +82,9 @@ git-blame ancillaryinterrogators
|
||||
git-branch mainporcelain
|
||||
git-bundle mainporcelain
|
||||
git-cat-file plumbinginterrogators
|
||||
git-checkout-index plumbingmanipulators
|
||||
git-checkout mainporcelain
|
||||
git-check-attr purehelpers
|
||||
git-checkout mainporcelain
|
||||
git-checkout-index plumbingmanipulators
|
||||
git-check-ref-format purehelpers
|
||||
git-cherry ancillaryinterrogators
|
||||
git-cherry-pick mainporcelain
|
||||
@@ -91,6 +93,7 @@ git-clean mainporcelain
|
||||
git-clone mainporcelain
|
||||
git-commit mainporcelain
|
||||
git-commit-tree plumbingmanipulators
|
||||
git-config ancillarymanipulators
|
||||
git-convert-objects ancillarymanipulators
|
||||
git-count-objects ancillaryinterrogators
|
||||
git-cvsexportcommit foreignscminterface
|
||||
@@ -98,9 +101,9 @@ git-cvsimport foreignscminterface
|
||||
git-cvsserver foreignscminterface
|
||||
git-daemon synchingrepositories
|
||||
git-describe mainporcelain
|
||||
git-diff mainporcelain
|
||||
git-diff-files plumbinginterrogators
|
||||
git-diff-index plumbinginterrogators
|
||||
git-diff mainporcelain
|
||||
git-diff-tree plumbinginterrogators
|
||||
git-fast-import ancillarymanipulators
|
||||
git-fetch mainporcelain
|
||||
@@ -130,13 +133,13 @@ git-ls-remote plumbinginterrogators
|
||||
git-ls-tree plumbinginterrogators
|
||||
git-mailinfo purehelpers
|
||||
git-mailsplit purehelpers
|
||||
git-merge mainporcelain
|
||||
git-merge-base plumbinginterrogators
|
||||
git-merge-file plumbingmanipulators
|
||||
git-merge-index plumbingmanipulators
|
||||
git-merge mainporcelain
|
||||
git-merge-one-file purehelpers
|
||||
git-merge-tree ancillaryinterrogators
|
||||
git-mergetool ancillarymanipulators
|
||||
git-merge-tree ancillaryinterrogators
|
||||
git-mktag plumbingmanipulators
|
||||
git-mktree plumbingmanipulators
|
||||
git-mv mainporcelain
|
||||
@@ -157,9 +160,8 @@ git-rebase mainporcelain
|
||||
git-receive-pack synchelpers
|
||||
git-reflog ancillarymanipulators
|
||||
git-relink ancillarymanipulators
|
||||
git-repack ancillarymanipulators
|
||||
git-config ancillarymanipulators
|
||||
git-remote ancillarymanipulators
|
||||
git-repack ancillarymanipulators
|
||||
git-request-pull foreignscminterface
|
||||
git-rerere ancillaryinterrogators
|
||||
git-reset mainporcelain
|
||||
|
||||
15
Documentation/fix-texi.perl
Executable file
15
Documentation/fix-texi.perl
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
while (<>) {
|
||||
if (/^\@setfilename/) {
|
||||
$_ = "\@setfilename git.info\n";
|
||||
} elsif (/^\@direntry/) {
|
||||
print '@dircategory Development
|
||||
@direntry
|
||||
* Git: (git). A fast distributed revision control system
|
||||
@end direntry
|
||||
'; }
|
||||
unless (/^\@direntry/../^\@end direntry/) {
|
||||
print;
|
||||
}
|
||||
}
|
||||
@@ -3,32 +3,37 @@ git-add(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-add - Add file contents to the changeset to be committed next
|
||||
git-add - Add file contents to the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-add' [-n] [-v] [-f] [--interactive | -i] [-u] [--] <file>...
|
||||
'git-add' [-n] [-v] [-f] [--interactive | -i] [-u] [--refresh] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
All the changed file contents to be committed together in a single set
|
||||
of changes must be "added" with the 'add' command before using the
|
||||
'commit' command. This is not only for adding new files. Even modified
|
||||
files must be added to the set of changes about to be committed.
|
||||
This command adds the current content of new or modified files to the
|
||||
index, thus staging that content for inclusion in the next commit.
|
||||
|
||||
This command can be performed multiple times before a commit. The added
|
||||
content corresponds to the state of specified file(s) at the time the
|
||||
'add' command is used. This means the 'commit' command will not consider
|
||||
subsequent changes to already added content if it is not added again before
|
||||
the commit.
|
||||
The "index" holds a snapshot of the content of the working tree, and it
|
||||
is this snapshot that is taken as the contents of the next commit. Thus
|
||||
after making any changes to the working directory, and before running
|
||||
the commit command, you must use the 'add' command to add any new or
|
||||
modified files to the index.
|
||||
|
||||
The 'git status' command can be used to obtain a summary of what is included
|
||||
for the next commit.
|
||||
This command can be performed multiple times before a commit. It only
|
||||
adds the content of the specified file(s) at the time the add command is
|
||||
run; if you want subsequent changes included in the next commit, then
|
||||
you must run 'git add' again to add the new content to the index.
|
||||
|
||||
This command can be used to add ignored files with `-f` (force)
|
||||
option, but they have to be
|
||||
explicitly and exactly specified from the command line. File globbing
|
||||
and recursive behaviour do not add ignored files.
|
||||
The 'git status' command can be used to obtain a summary of which
|
||||
files have changes that are staged for the next commit.
|
||||
|
||||
The 'git add' command will not add ignored files by default. If any
|
||||
ignored files were explicitly specified on the command line, 'git add'
|
||||
will fail with a list of ignored files. Ignored files reached by
|
||||
directory recursion or filename globbing will be silently ignored.
|
||||
The 'add' command can be used to add ignored files with the `-f`
|
||||
(force) option.
|
||||
|
||||
Please see gitlink:git-commit[1] for alternative ways to add content to a
|
||||
commit.
|
||||
@@ -63,6 +68,10 @@ OPTIONS
|
||||
command line. If no paths are specified, all tracked files are
|
||||
updated.
|
||||
|
||||
\--refresh::
|
||||
Don't add the file(s), but only refresh their stat()
|
||||
information in the index.
|
||||
|
||||
\--::
|
||||
This option can be used to separate command-line options from
|
||||
the list of files, (useful when filenames might be mistaken
|
||||
|
||||
@@ -171,6 +171,20 @@ apply.whitespace::
|
||||
When no `--whitespace` flag is given from the command
|
||||
line, this configuration item is used as the default.
|
||||
|
||||
Submodules
|
||||
----------
|
||||
If the patch contains any changes to submodules then gitlink:git-apply[1]
|
||||
treats these changes as follows.
|
||||
|
||||
If --index is specified (explicitly or implicitly), then the submodule
|
||||
commits must match the index exactly for the patch to apply. If any
|
||||
of the submodules are checked-out, then these check-outs are completely
|
||||
ignored, i.e., they are not required to be up-to-date or clean and they
|
||||
are not updated.
|
||||
|
||||
If --index is not specified, then the submodule commits in the patch
|
||||
are ignored and only the absence of presence of the corresponding
|
||||
subdirectory is checked and (if possible) updated.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -9,7 +9,8 @@ git-clone - Clone a repository into a new directory
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
|
||||
'git-clone' [--template=<template_directory>]
|
||||
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare]
|
||||
[-o <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[--depth <depth>] <repository> [<directory>]
|
||||
|
||||
@@ -40,8 +41,19 @@ OPTIONS
|
||||
this flag bypasses normal "git aware" transport
|
||||
mechanism and clones the repository by making a copy of
|
||||
HEAD and everything under objects and refs directories.
|
||||
The files under .git/objects/ directory are hardlinked
|
||||
to save space when possible.
|
||||
The files under `.git/objects/` directory are hardlinked
|
||||
to save space when possible. This is now the default when
|
||||
the source repository is specified with `/path/to/repo`
|
||||
syntax, so it essentially is a no-op option. To force
|
||||
copying instead of hardlinking (which may be desirable
|
||||
if you are trying to make a back-up of your repository),
|
||||
but still avoid the usual "git aware" transport
|
||||
mechanism, `--no-hardlinks` can be used.
|
||||
|
||||
--no-hardlinks::
|
||||
Optimize the cloning process from a repository on a
|
||||
local filesystem by copying files under `.git/objects`
|
||||
directory.
|
||||
|
||||
--shared::
|
||||
-s::
|
||||
|
||||
@@ -15,26 +15,27 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Use 'git commit' when you want to record your changes into the repository
|
||||
along with a log message describing what the commit is about. All changes
|
||||
to be committed must be explicitly identified using one of the following
|
||||
methods:
|
||||
Use 'git commit' to store the current contents of the index in a new
|
||||
commit along with a log message describing the changes you have made.
|
||||
|
||||
The content to be added can be specified in several ways:
|
||||
|
||||
1. by using gitlink:git-add[1] to incrementally "add" changes to the
|
||||
next commit before using the 'commit' command (Note: even modified
|
||||
index before using the 'commit' command (Note: even modified
|
||||
files must be "added");
|
||||
|
||||
2. by using gitlink:git-rm[1] to identify content removal for the next
|
||||
commit, again before using the 'commit' command;
|
||||
2. by using gitlink:git-rm[1] to remove files from the working tree
|
||||
and the index, again before using the 'commit' command;
|
||||
|
||||
3. by directly listing files containing changes to be committed as arguments
|
||||
to the 'commit' command, in which cases only those files alone will be
|
||||
considered for the commit;
|
||||
3. by listing files as arguments to the 'commit' command, in which
|
||||
case the commit will ignore changes staged in the index, and instead
|
||||
record the current content of the listed files;
|
||||
|
||||
4. by using the -a switch with the 'commit' command to automatically "add"
|
||||
changes from all known files i.e. files that have already been committed
|
||||
before, and to automatically "rm" files that have been
|
||||
removed from the working tree, and perform the actual commit.
|
||||
4. by using the -a switch with the 'commit' command to automatically
|
||||
"add" changes from all known files (i.e. all files that are already
|
||||
listed in the index) and to automatically "rm" files in the index
|
||||
that have been removed from the working tree, and then perform the
|
||||
actual commit;
|
||||
|
||||
5. by using the --interactive switch with the 'commit' command to decide one
|
||||
by one which files should be part of the commit, before finalizing the
|
||||
|
||||
@@ -64,6 +64,13 @@ include::pretty-options.txt[]
|
||||
--follow::
|
||||
Continue listing the history of a file beyond renames.
|
||||
|
||||
--log-size::
|
||||
Before the log message print out its size in bytes. Intended
|
||||
mainly for porcelain tools consumption. If git is unable to
|
||||
produce a valid value size is set to zero.
|
||||
Note that only message is considered, if also a diff is shown
|
||||
its size is not included.
|
||||
|
||||
<paths>...::
|
||||
Show only commits that affect the specified paths.
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ the remote repository.
|
||||
|
||||
-f, \--force::
|
||||
Usually, the command refuses to update a remote ref that is
|
||||
not a descendant of the local ref used to overwrite it.
|
||||
not an ancestor of the local ref used to overwrite it.
|
||||
This flag disables the check. This can cause the
|
||||
remote repository to lose commits; use it with care.
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ the following situation:
|
||||
|
||||
then the command
|
||||
|
||||
git-rebase --onto topicA~5 topicA~2 topicA
|
||||
git-rebase --onto topicA~5 topicA~3 topicA
|
||||
|
||||
would result in the removal of commits F and G:
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ left-to-right.
|
||||
G H I J
|
||||
\ / \ /
|
||||
D E F
|
||||
\ | / \
|
||||
\ | / \
|
||||
\ | / |
|
||||
\|/ |
|
||||
B C
|
||||
|
||||
@@ -29,8 +29,8 @@ you create one.
|
||||
|
||||
The latest stash you created is stored in `$GIT_DIR/refs/stash`; older
|
||||
stashes are found in the reflog of this reference and can be named using
|
||||
the usual reflog syntax (e.g. `stash@\{1}` is the most recently
|
||||
created stash, `stash@\{2}` is the one before it, `stash@\{2.hours.ago}`
|
||||
the usual reflog syntax (e.g. `stash@\{0}` is the most recently
|
||||
created stash, `stash@\{1}` is the one before it, `stash@\{2.hours.ago}`
|
||||
is also possible).
|
||||
|
||||
OPTIONS
|
||||
@@ -45,7 +45,7 @@ save::
|
||||
list::
|
||||
|
||||
List the stashes that you currently have. Each 'stash' is listed
|
||||
with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1} is
|
||||
with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1}` is
|
||||
the one before, etc.), the name of the branch that was current when the
|
||||
stash was made, and a short description of the commit the stash was
|
||||
based on.
|
||||
@@ -61,7 +61,7 @@ show [<stash>]::
|
||||
stashed state and its original parent. When no `<stash>` is given,
|
||||
shows the latest one. By default, the command shows the diffstat, but
|
||||
it will accept any format known to `git-diff` (e.g., `git-stash show
|
||||
-p stash@\{2}` to view the second most recent stash in patch form).
|
||||
-p stash@\{1}` to view the second most recent stash in patch form).
|
||||
|
||||
apply [<stash>]::
|
||||
|
||||
|
||||
@@ -27,6 +27,13 @@ The command takes the same set of options as `git-commit`; it
|
||||
shows what would be committed if the same options are given to
|
||||
`git-commit`.
|
||||
|
||||
If any paths have been touched in the working tree (that is,
|
||||
their modification times have changed) but their contents and
|
||||
permissions are identical to those in the index file, the command
|
||||
updates the index file. Running `git-status` can thus speed up
|
||||
subsequent operations such as `git-diff` if the working tree
|
||||
contains many paths that have been touched but not modified.
|
||||
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
|
||||
@@ -8,7 +8,7 @@ git-stripspace - Filter out empty lines
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-stripspace' < <stream>
|
||||
'git-stripspace' [-s | --strip-comments] < <stream>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -16,6 +16,9 @@ Remove multiple empty lines, and empty lines at beginning and end.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-s\|--strip-comments::
|
||||
In addition to empty lines, also strip lines starting with '#'.
|
||||
|
||||
<stream>::
|
||||
Byte stream to act on.
|
||||
|
||||
|
||||
@@ -435,6 +435,26 @@ Tracking and contributing to an entire Subversion-managed project
|
||||
# of dcommit/rebase/show-ignore should be the same as above.
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The initial 'git-svn clone' can be quite time-consuming
|
||||
(especially for large Subversion repositories). If multiple
|
||||
people (or one person with multiple machines) want to use
|
||||
git-svn to interact with the same Subversion repository, you can
|
||||
do the initial 'git-svn clone' to a repository on a server and
|
||||
have each person clone that repository with 'git clone':
|
||||
|
||||
------------------------------------------------------------------------
|
||||
# Do the initial import on a server
|
||||
ssh server "cd /pub && git-svn clone http://svn.foo.org/project
|
||||
# Clone locally
|
||||
git clone server:/pub/project
|
||||
# Tell git-svn which branch contains the Subversion commits
|
||||
git update-ref refs/remotes/git-svn origin/master
|
||||
# Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server)
|
||||
git-svn init http://svn.foo.org/project
|
||||
# Pull the latest changes from Subversion
|
||||
git-svn rebase
|
||||
------------------------------------------------------------------------
|
||||
|
||||
REBASE VS. PULL/MERGE
|
||||
---------------------
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ SYNOPSIS
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <name> [<head>]
|
||||
'git-tag' -d <name>...
|
||||
'git-tag' [-n [<num>]] -l [<pattern>]
|
||||
'git-tag' -v <name>
|
||||
'git-tag' -v <name>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -23,7 +23,7 @@ Unless `-f` is given, the tag must not yet exist in
|
||||
|
||||
If one of `-a`, `-s`, or `-u <key-id>` is passed, the command
|
||||
creates a 'tag' object, and requires the tag message. Unless
|
||||
`-m <msg>` is given, an editor is started for the user to type
|
||||
`-m <msg>` or `-F <file>` is given, an editor is started for the user to type
|
||||
in the tag message.
|
||||
|
||||
Otherwise just the SHA1 object name of the commit object is
|
||||
@@ -59,15 +59,17 @@ OPTIONS
|
||||
Delete existing tags with the given names.
|
||||
|
||||
-v::
|
||||
Verify the gpg signature of given the tag
|
||||
Verify the gpg signature of the given tag names.
|
||||
|
||||
-n <num>::
|
||||
<num> specifies how many lines from the annotation, if any,
|
||||
are printed when using -l.
|
||||
The default is not to print any annotation lines.
|
||||
If no number is given to `-n`, only the first line is printed.
|
||||
|
||||
-l <pattern>::
|
||||
List tags with names that match the given pattern (or all if no pattern is given).
|
||||
Typing "git tag" without arguments, also lists all tags.
|
||||
|
||||
-m <msg>::
|
||||
Use the given tag message (instead of prompting)
|
||||
|
||||
@@ -3,11 +3,11 @@ git-verify-tag(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-verify-tag - Check the GPG signature of tag
|
||||
git-verify-tag - Check the GPG signature of tags
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-verify-tag' <tag>
|
||||
'git-verify-tag' <tag>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
@@ -42,9 +42,10 @@ 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.2.4/git.html[documentation for release 1.5.2.4]
|
||||
* link:v1.5.2.5/git.html[documentation for release 1.5.2.5]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.5.2.5.txt[1.5.2.5],
|
||||
link:RelNotes-1.5.2.4.txt[1.5.2.4],
|
||||
link:RelNotes-1.5.2.3.txt[1.5.2.3],
|
||||
link:RelNotes-1.5.2.2.txt[1.5.2.2],
|
||||
@@ -421,6 +422,22 @@ other
|
||||
to an empty string or to the value "cat", git will not launch
|
||||
a pager.
|
||||
|
||||
'GIT_SSH'::
|
||||
If this environment variable is set then gitlink:git-fetch[1]
|
||||
and gitlink:git-push[1] will use this command instead
|
||||
of `ssh` when they need to connect to a remote system.
|
||||
The 'GIT_SSH' command will be given exactly two arguments:
|
||||
the 'username@host' (or just 'host') from the URL and the
|
||||
shell command to execute on that remote system.
|
||||
+
|
||||
To pass options to the program that you want to list in GIT_SSH
|
||||
you will need to wrap the program and options into a shell script,
|
||||
then set GIT_SSH to refer to the shell script.
|
||||
+
|
||||
Usually it is easier to configure any desired options through your
|
||||
personal `.ssh/config` file. Please consult your ssh documentation
|
||||
for further details.
|
||||
|
||||
'GIT_FLUSH'::
|
||||
If this environment variable is set to "1", then commands such
|
||||
as git-blame (in incremental mode), git-rev-list, git-log,
|
||||
|
||||
@@ -7,7 +7,7 @@ mandir="$2"
|
||||
SUBDIRECTORY_OK=t
|
||||
USAGE='<refname> <target directory>'
|
||||
. git-sh-setup
|
||||
export GIT_DIR
|
||||
cd_to_toplevel
|
||||
|
||||
test -z "$mandir" && usage
|
||||
if ! git rev-parse --verify "$head^0" >/dev/null; then
|
||||
@@ -18,14 +18,14 @@ fi
|
||||
GIT_INDEX_FILE=`pwd`/.quick-doc.index
|
||||
export GIT_INDEX_FILE
|
||||
rm -f "$GIT_INDEX_FILE"
|
||||
trap 'rm -f "$GIT_INDEX_FILE"' 0
|
||||
|
||||
git read-tree $head
|
||||
git checkout-index -a -f --prefix="$mandir"/
|
||||
|
||||
if test -n "$GZ"; then
|
||||
cd "$mandir"
|
||||
for i in `git ls-tree -r --name-only $head`
|
||||
do
|
||||
gzip < $i > $i.gz && rm $i
|
||||
done
|
||||
git ls-tree -r --name-only $head |
|
||||
xargs printf "$mandir/%s\n" |
|
||||
xargs gzip -f
|
||||
fi
|
||||
rm -f "$GIT_INDEX_FILE"
|
||||
|
||||
@@ -15,11 +15,11 @@ to name the remote repository:
|
||||
- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git
|
||||
===============================================================
|
||||
|
||||
SSH is the default transport protocol. You can optionally specify
|
||||
which user to log-in as, and an alternate, scp-like syntax is also
|
||||
supported. Both syntaxes support username expansion,
|
||||
as does the native git protocol. The following three are
|
||||
identical to the last three above, respectively:
|
||||
SSH is the default transport protocol over the network. You can
|
||||
optionally specify which user to log-in as, and an alternate,
|
||||
scp-like syntax is also supported. Both syntaxes support
|
||||
username expansion, as does the native git protocol. The following
|
||||
three are identical to the last three above, respectively:
|
||||
|
||||
===============================================================
|
||||
- {startsb}user@{endsb}host.xz:/path/to/repo.git/
|
||||
@@ -27,8 +27,12 @@ identical to the last three above, respectively:
|
||||
- {startsb}user@{endsb}host.xz:path/to/repo.git
|
||||
===============================================================
|
||||
|
||||
To sync with a local directory, use:
|
||||
To sync with a local directory, you can use:
|
||||
|
||||
===============================================================
|
||||
- /path/to/repo.git/
|
||||
- file:///path/to/repo.git/
|
||||
===============================================================
|
||||
|
||||
They are mostly equivalent, except when cloning. See
|
||||
gitlink:git-clone[1] for details.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Git User's Manual (for version 1.5.1 or newer)
|
||||
Git User's Manual (for version 1.5.3 or newer)
|
||||
______________________________________________
|
||||
|
||||
|
||||
@@ -1079,6 +1079,11 @@ $ git diff HEAD # difference between HEAD and working tree; what
|
||||
$ git status # a brief per-file summary of the above.
|
||||
-------------------------------------------------
|
||||
|
||||
You can also use gitlink:git-gui[1] to create commits, view changes in
|
||||
the index and the working tree files, and individually select diff hunks
|
||||
for inclusion in the index (by right-clicking on the diff hunk and
|
||||
choosing "Stage Hunk For Commit").
|
||||
|
||||
[[creating-good-commit-messages]]
|
||||
Creating good commit messages
|
||||
-----------------------------
|
||||
@@ -1484,6 +1489,38 @@ $ git show HEAD^:path/to/file
|
||||
|
||||
which will display the given version of the file.
|
||||
|
||||
[[interrupted-work]]
|
||||
Temporarily setting aside work in progress
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While you are in the middle of working on something complicated, you
|
||||
find an unrelated but obvious and trivial bug. You would like to fix it
|
||||
before continuing. You can use gitlink:git-stash[1] to save the current
|
||||
state of your work, and after fixing the bug (or, optionally after doing
|
||||
so on a different branch and then coming back), unstash the
|
||||
work-in-progress changes.
|
||||
|
||||
------------------------------------------------
|
||||
$ git stash "work in progress for foo feature"
|
||||
------------------------------------------------
|
||||
|
||||
This command will save your changes away to the `stash`, and
|
||||
reset your working tree and the index to match the tip of your
|
||||
current branch. Then you can make your fix as usual.
|
||||
|
||||
------------------------------------------------
|
||||
... edit and test ...
|
||||
$ git commit -a -m "blorpl: typofix"
|
||||
------------------------------------------------
|
||||
|
||||
After that, you can go back to what you were working on with
|
||||
`git stash apply`:
|
||||
|
||||
------------------------------------------------
|
||||
$ git stash apply
|
||||
------------------------------------------------
|
||||
|
||||
|
||||
[[ensuring-good-performance]]
|
||||
Ensuring good performance
|
||||
-------------------------
|
||||
@@ -1667,24 +1704,19 @@ one step:
|
||||
$ git pull origin master
|
||||
-------------------------------------------------
|
||||
|
||||
In fact, "origin" is normally the default repository to pull from,
|
||||
and the default branch is normally the HEAD of the remote repository,
|
||||
so often you can accomplish the above with just
|
||||
In fact, if you have "master" checked out, then by default "git pull"
|
||||
merges from the HEAD branch of the origin repository. So often you can
|
||||
accomplish the above with just a simple
|
||||
|
||||
-------------------------------------------------
|
||||
$ git pull
|
||||
-------------------------------------------------
|
||||
|
||||
See the descriptions of the branch.<name>.remote and branch.<name>.merge
|
||||
options in gitlink:git-config[1] to learn how to control these defaults
|
||||
depending on the current branch. Also note that the --track option to
|
||||
gitlink:git-branch[1] and gitlink:git-checkout[1] can be used to
|
||||
automatically set the default remote branch to pull from at the time
|
||||
that a branch is created:
|
||||
|
||||
-------------------------------------------------
|
||||
$ git checkout --track -b maint origin/maint
|
||||
-------------------------------------------------
|
||||
More generally, a branch that is created from a remote branch will pull
|
||||
by default from that branch. See the descriptions of the
|
||||
branch.<name>.remote and branch.<name>.merge options in
|
||||
gitlink:git-config[1], and the discussion of the --track option in
|
||||
gitlink:git-checkout[1], to learn how to control these defaults.
|
||||
|
||||
In addition to saving you keystrokes, "git pull" also helps you by
|
||||
producing a default commit message documenting the branch and
|
||||
@@ -2479,8 +2511,10 @@ $ gitk origin..mywork &
|
||||
|
||||
And browse through the list of patches in the mywork branch using gitk,
|
||||
applying them (possibly in a different order) to mywork-new using
|
||||
cherry-pick, and possibly modifying them as you go using commit
|
||||
--amend.
|
||||
cherry-pick, and possibly modifying them as you go using commit --amend.
|
||||
The git-gui[1] command may also help as it allows you to individually
|
||||
select diff hunks for inclusion in the index (by right-clicking on the
|
||||
diff hunk and choosing "Stage Hunk for Commit").
|
||||
|
||||
Another technique is to use git-format-patch to create a series of
|
||||
patches, then reset the state to before the patches:
|
||||
|
||||
18
INSTALL
18
INSTALL
@@ -5,8 +5,8 @@ Normally you can just do "make" followed by "make install", and that
|
||||
will install the git programs in your own ~/bin/ directory. If you want
|
||||
to do a global install, you can do
|
||||
|
||||
$ make prefix=/usr all doc ;# as yourself
|
||||
# make prefix=/usr install install-doc ;# as root
|
||||
$ make prefix=/usr all doc info ;# as yourself
|
||||
# make prefix=/usr install install-doc install-info ;# as root
|
||||
|
||||
(or prefix=/usr/local, of course). Just like any program suite
|
||||
that uses $prefix, the built results have some paths encoded,
|
||||
@@ -91,9 +91,13 @@ Issues of note:
|
||||
- To build and install documentation suite, you need to have
|
||||
the asciidoc/xmlto toolchain. Because not many people are
|
||||
inclined to install the tools, the default build target
|
||||
("make all") does _not_ build them. The documentation is
|
||||
written for AsciiDoc 7, but "make ASCIIDOC8=YesPlease doc"
|
||||
will let you format with AsciiDoc 8.
|
||||
("make all") does _not_ build them.
|
||||
|
||||
Building and installing the info file additionally requires
|
||||
makeinfo and docbook2X. Version 0.8.3 is known to work.
|
||||
|
||||
The documentation is written for AsciiDoc 7, but "make
|
||||
ASCIIDOC8=YesPlease doc" will let you format with AsciiDoc 8.
|
||||
|
||||
Alternatively, pre-formatted documentation are available in
|
||||
"html" and "man" branches of the git repository itself. For
|
||||
@@ -116,3 +120,7 @@ Issues of note:
|
||||
would instead give you a copy of what you see at:
|
||||
|
||||
http://www.kernel.org/pub/software/scm/git/docs/
|
||||
|
||||
It has been reported that docbook-xsl version 1.72 and 1.73 are
|
||||
buggy; 1.72 misformats manual pages for callouts, and 1.73 needs
|
||||
the patch in contrib/patches/docbook-xsl-manpages-charmap.patch
|
||||
|
||||
9
Makefile
9
Makefile
@@ -208,7 +208,6 @@ SCRIPT_SH = \
|
||||
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
|
||||
git-repack.sh git-request-pull.sh git-reset.sh \
|
||||
git-sh-setup.sh \
|
||||
git-tag.sh git-verify-tag.sh \
|
||||
git-am.sh \
|
||||
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
|
||||
git-merge-resolve.sh git-merge-ours.sh \
|
||||
@@ -364,12 +363,14 @@ BUILTIN_OBJS = \
|
||||
builtin-show-branch.o \
|
||||
builtin-stripspace.o \
|
||||
builtin-symbolic-ref.o \
|
||||
builtin-tag.o \
|
||||
builtin-tar-tree.o \
|
||||
builtin-unpack-objects.o \
|
||||
builtin-update-index.o \
|
||||
builtin-update-ref.o \
|
||||
builtin-upload-archive.o \
|
||||
builtin-verify-pack.o \
|
||||
builtin-verify-tag.o \
|
||||
builtin-write-tree.o \
|
||||
builtin-show-ref.o \
|
||||
builtin-pack-refs.o
|
||||
@@ -941,6 +942,9 @@ perl/Makefile: perl/Git.pm perl/Makefile.PL GIT-CFLAGS
|
||||
doc:
|
||||
$(MAKE) -C Documentation all
|
||||
|
||||
info:
|
||||
$(MAKE) -C Documentation info
|
||||
|
||||
TAGS:
|
||||
$(RM) TAGS
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs etags -a
|
||||
@@ -1030,6 +1034,9 @@ endif
|
||||
install-doc:
|
||||
$(MAKE) -C Documentation install
|
||||
|
||||
install-info:
|
||||
$(MAKE) -C Documentation install-info
|
||||
|
||||
quick-install-doc:
|
||||
$(MAKE) -C Documentation quick-install
|
||||
|
||||
|
||||
120
attr.c
120
attr.c
@@ -257,6 +257,7 @@ static struct attr_stack {
|
||||
struct attr_stack *prev;
|
||||
char *origin;
|
||||
unsigned num_matches;
|
||||
unsigned alloc;
|
||||
struct match_attr **attrs;
|
||||
} *attr_stack;
|
||||
|
||||
@@ -287,6 +288,26 @@ static const char *builtin_attr[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void handle_attr_line(struct attr_stack *res,
|
||||
const char *line,
|
||||
const char *src,
|
||||
int lineno,
|
||||
int macro_ok)
|
||||
{
|
||||
struct match_attr *a;
|
||||
|
||||
a = parse_attr_line(line, src, lineno, macro_ok);
|
||||
if (!a)
|
||||
return;
|
||||
if (res->alloc <= res->num_matches) {
|
||||
res->alloc = alloc_nr(res->num_matches);
|
||||
res->attrs = xrealloc(res->attrs,
|
||||
sizeof(struct match_attr *) *
|
||||
res->alloc);
|
||||
}
|
||||
res->attrs[res->num_matches++] = a;
|
||||
}
|
||||
|
||||
static struct attr_stack *read_attr_from_array(const char **list)
|
||||
{
|
||||
struct attr_stack *res;
|
||||
@@ -294,42 +315,91 @@ static struct attr_stack *read_attr_from_array(const char **list)
|
||||
int lineno = 0;
|
||||
|
||||
res = xcalloc(1, sizeof(*res));
|
||||
while ((line = *(list++)) != NULL) {
|
||||
struct match_attr *a;
|
||||
|
||||
a = parse_attr_line(line, "[builtin]", ++lineno, 1);
|
||||
if (!a)
|
||||
continue;
|
||||
res->attrs = xrealloc(res->attrs,
|
||||
sizeof(struct match_attr *) * (res->num_matches + 1));
|
||||
res->attrs[res->num_matches++] = a;
|
||||
}
|
||||
while ((line = *(list++)) != NULL)
|
||||
handle_attr_line(res, line, "[builtin]", ++lineno, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
|
||||
{
|
||||
FILE *fp;
|
||||
FILE *fp = fopen(path, "r");
|
||||
struct attr_stack *res;
|
||||
char buf[2048];
|
||||
int lineno = 0;
|
||||
|
||||
res = xcalloc(1, sizeof(*res));
|
||||
fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
res = xcalloc(1, sizeof(*res));
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
handle_attr_line(res, buf, path, ++lineno, macro_ok);
|
||||
fclose(fp);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *read_index_data(const char *path)
|
||||
{
|
||||
int pos, len;
|
||||
unsigned long sz;
|
||||
enum object_type type;
|
||||
void *data;
|
||||
|
||||
len = strlen(path);
|
||||
pos = cache_name_pos(path, len);
|
||||
if (pos < 0) {
|
||||
/*
|
||||
* We might be in the middle of a merge, in which
|
||||
* case we would read stage #2 (ours).
|
||||
*/
|
||||
int i;
|
||||
for (i = -pos - 1;
|
||||
(pos < 0 && i < active_nr &&
|
||||
!strcmp(active_cache[i]->name, path));
|
||||
i++)
|
||||
if (ce_stage(active_cache[i]) == 2)
|
||||
pos = i;
|
||||
}
|
||||
if (pos < 0)
|
||||
return NULL;
|
||||
data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
|
||||
if (!data || type != OBJ_BLOB) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct attr_stack *read_attr(const char *path, int macro_ok)
|
||||
{
|
||||
struct attr_stack *res;
|
||||
char *buf, *sp;
|
||||
int lineno = 0;
|
||||
|
||||
res = read_attr_from_file(path, macro_ok);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
struct match_attr *a;
|
||||
res = xcalloc(1, sizeof(*res));
|
||||
|
||||
a = parse_attr_line(buf, path, ++lineno, macro_ok);
|
||||
if (!a)
|
||||
continue;
|
||||
res->attrs = xrealloc(res->attrs,
|
||||
sizeof(struct match_attr *) * (res->num_matches + 1));
|
||||
res->attrs[res->num_matches++] = a;
|
||||
/*
|
||||
* There is no checked out .gitattributes file there, but
|
||||
* we might have it in the index. We allow operation in a
|
||||
* sparsely checked out work tree, so read from it.
|
||||
*/
|
||||
buf = read_index_data(path);
|
||||
if (!buf)
|
||||
return res;
|
||||
|
||||
for (sp = buf; *sp; ) {
|
||||
char *ep;
|
||||
int more;
|
||||
for (ep = sp; *ep && *ep != '\n'; ep++)
|
||||
;
|
||||
more = (*ep == '\n');
|
||||
*ep = '\0';
|
||||
handle_attr_line(res, sp, path, ++lineno, macro_ok);
|
||||
sp = ep + more;
|
||||
}
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -370,13 +440,15 @@ static void bootstrap_attr_stack(void)
|
||||
elem->prev = attr_stack;
|
||||
attr_stack = elem;
|
||||
|
||||
elem = read_attr_from_file(GITATTRIBUTES_FILE, 1);
|
||||
elem = read_attr(GITATTRIBUTES_FILE, 1);
|
||||
elem->origin = strdup("");
|
||||
elem->prev = attr_stack;
|
||||
attr_stack = elem;
|
||||
debug_push(elem);
|
||||
|
||||
elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
|
||||
if (!elem)
|
||||
elem = xcalloc(1, sizeof(*elem));
|
||||
elem->origin = NULL;
|
||||
elem->prev = attr_stack;
|
||||
attr_stack = elem;
|
||||
@@ -441,7 +513,7 @@ static void prepare_attr_stack(const char *path, int dirlen)
|
||||
memcpy(pathbuf + dirlen, "/", 2);
|
||||
cp = strchr(pathbuf + len + 1, '/');
|
||||
strcpy(cp + 1, GITATTRIBUTES_FILE);
|
||||
elem = read_attr_from_file(pathbuf, 0);
|
||||
elem = read_attr(pathbuf, 0);
|
||||
*cp = '\0';
|
||||
elem->origin = strdup(pathbuf);
|
||||
elem->prev = attr_stack;
|
||||
|
||||
@@ -102,6 +102,7 @@ static void update_callback(struct diff_queue_struct *q,
|
||||
break;
|
||||
case DIFF_STATUS_DELETED:
|
||||
remove_file_from_cache(path);
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
if (verbose)
|
||||
printf("remove '%s'\n", path);
|
||||
break;
|
||||
@@ -109,12 +110,12 @@ static void update_callback(struct diff_queue_struct *q,
|
||||
}
|
||||
}
|
||||
|
||||
static void update(int verbose, const char **files)
|
||||
static void update(int verbose, const char *prefix, const char **files)
|
||||
{
|
||||
struct rev_info rev;
|
||||
init_revisions(&rev, "");
|
||||
init_revisions(&rev, prefix);
|
||||
setup_revisions(0, NULL, &rev, NULL);
|
||||
rev.prune_data = get_pathspec(rev.prefix, files);
|
||||
rev.prune_data = get_pathspec(prefix, files);
|
||||
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = update_callback;
|
||||
rev.diffopt.format_callback_data = &verbose;
|
||||
@@ -123,6 +124,23 @@ static void update(int verbose, const char **files)
|
||||
run_diff_files(&rev, 0);
|
||||
}
|
||||
|
||||
static void refresh(int verbose, const char **pathspec)
|
||||
{
|
||||
char *seen;
|
||||
int i, specs;
|
||||
|
||||
for (specs = 0; pathspec[specs]; specs++)
|
||||
/* nothing */;
|
||||
seen = xcalloc(specs, 1);
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
refresh_index(&the_index, verbose ? 0 : REFRESH_QUIET, pathspec, seen);
|
||||
for (i = 0; i < specs; i++) {
|
||||
if (!seen[i])
|
||||
die("pathspec '%s' did not match any files", pathspec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int git_add_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "core.excludesfile")) {
|
||||
@@ -143,7 +161,7 @@ static const char ignore_warning[] =
|
||||
int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd;
|
||||
int verbose = 0, show_only = 0, ignored_too = 0;
|
||||
int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
||||
const char **pathspec;
|
||||
struct dir_struct dir;
|
||||
int add_interactive = 0;
|
||||
@@ -191,11 +209,15 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
take_worktree_changes = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--refresh")) {
|
||||
refresh_only = 1;
|
||||
continue;
|
||||
}
|
||||
usage(builtin_add_usage);
|
||||
}
|
||||
|
||||
if (take_worktree_changes) {
|
||||
update(verbose, argv + i);
|
||||
update(verbose, prefix, argv + i);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@@ -206,6 +228,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
if (refresh_only) {
|
||||
refresh(verbose, pathspec);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fill_directory(&dir, pathspec, ignored_too);
|
||||
|
||||
if (show_only) {
|
||||
|
||||
113
builtin-apply.c
113
builtin-apply.c
@@ -1984,6 +1984,25 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p,
|
||||
unsigned long *size_p)
|
||||
{
|
||||
if (!ce)
|
||||
return 0;
|
||||
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||
*buf_p = xmalloc(100);
|
||||
*size_p = snprintf(*buf_p, 100,
|
||||
"Subproject commit %s\n", sha1_to_hex(ce->sha1));
|
||||
} else {
|
||||
enum object_type type;
|
||||
*buf_p = read_sha1_file(ce->sha1, &type, size_p);
|
||||
if (!*buf_p)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
|
||||
{
|
||||
char *buf;
|
||||
@@ -1994,22 +2013,32 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
||||
alloc = 0;
|
||||
buf = NULL;
|
||||
if (cached) {
|
||||
if (ce) {
|
||||
enum object_type type;
|
||||
buf = read_sha1_file(ce->sha1, &type, &size);
|
||||
if (!buf)
|
||||
if (read_file_or_gitlink(ce, &buf, &size))
|
||||
return error("read of %s failed", patch->old_name);
|
||||
alloc = size;
|
||||
} else if (patch->old_name) {
|
||||
if (S_ISGITLINK(patch->old_mode)) {
|
||||
if (ce)
|
||||
read_file_or_gitlink(ce, &buf, &size);
|
||||
else {
|
||||
/*
|
||||
* There is no way to apply subproject
|
||||
* patch without looking at the index.
|
||||
*/
|
||||
patch->fragments = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
size = xsize_t(st->st_size);
|
||||
alloc = size + 8192;
|
||||
buf = xmalloc(alloc);
|
||||
if (read_old_data(st, patch->old_name,
|
||||
&buf, &alloc, &size))
|
||||
return error("read of %s failed",
|
||||
patch->old_name);
|
||||
alloc = size;
|
||||
}
|
||||
}
|
||||
else if (patch->old_name) {
|
||||
size = xsize_t(st->st_size);
|
||||
alloc = size + 8192;
|
||||
buf = xmalloc(alloc);
|
||||
if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
|
||||
return error("read of %s failed", patch->old_name);
|
||||
}
|
||||
|
||||
desc.size = size;
|
||||
desc.alloc = alloc;
|
||||
@@ -2055,6 +2084,16 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_index_match(struct cache_entry *ce, struct stat *st)
|
||||
{
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||
if (!S_ISDIR(st->st_mode))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
return ce_match_stat(ce, st, 1);
|
||||
}
|
||||
|
||||
static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
{
|
||||
struct stat st;
|
||||
@@ -2065,8 +2104,14 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
int ok_if_exists;
|
||||
|
||||
patch->rejected = 1; /* we will drop this after we succeed */
|
||||
|
||||
/*
|
||||
* Make sure that we do not have local modifications from the
|
||||
* index when we are looking at the index. Also make sure
|
||||
* we have the preimage file to be patched in the work tree,
|
||||
* unless --cached, which tells git to apply only in the index.
|
||||
*/
|
||||
if (old_name) {
|
||||
int changed = 0;
|
||||
int stat_ret = 0;
|
||||
unsigned st_mode = 0;
|
||||
|
||||
@@ -2096,15 +2141,12 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
lstat(old_name, &st))
|
||||
return -1;
|
||||
}
|
||||
if (!cached)
|
||||
changed = ce_match_stat(ce, &st, 1);
|
||||
if (changed)
|
||||
if (!cached && verify_index_match(ce, &st))
|
||||
return error("%s: does not match index",
|
||||
old_name);
|
||||
if (cached)
|
||||
st_mode = ntohl(ce->ce_mode);
|
||||
}
|
||||
else if (stat_ret < 0)
|
||||
} else if (stat_ret < 0)
|
||||
return error("%s: %s", old_name, strerror(errno));
|
||||
|
||||
if (!cached)
|
||||
@@ -2354,7 +2396,11 @@ static void remove_file(struct patch *patch, int rmdir_empty)
|
||||
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
|
||||
}
|
||||
if (!cached) {
|
||||
if (!unlink(patch->old_name) && rmdir_empty) {
|
||||
if (S_ISGITLINK(patch->old_mode)) {
|
||||
if (rmdir(patch->old_name))
|
||||
warning("unable to remove submodule %s",
|
||||
patch->old_name);
|
||||
} else if (!unlink(patch->old_name) && rmdir_empty) {
|
||||
char *name = xstrdup(patch->old_name);
|
||||
char *end = strrchr(name, '/');
|
||||
while (end) {
|
||||
@@ -2382,13 +2428,21 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
|
||||
memcpy(ce->name, path, namelen);
|
||||
ce->ce_mode = create_ce_mode(mode);
|
||||
ce->ce_flags = htons(namelen);
|
||||
if (!cached) {
|
||||
if (lstat(path, &st) < 0)
|
||||
die("unable to stat newly created file %s", path);
|
||||
fill_stat_cache_info(ce, &st);
|
||||
if (S_ISGITLINK(mode)) {
|
||||
const char *s = buf;
|
||||
|
||||
if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
|
||||
die("corrupt patch for subproject %s", path);
|
||||
} else {
|
||||
if (!cached) {
|
||||
if (lstat(path, &st) < 0)
|
||||
die("unable to stat newly created file %s",
|
||||
path);
|
||||
fill_stat_cache_info(ce, &st);
|
||||
}
|
||||
if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
|
||||
die("unable to create backing store for newly created file %s", path);
|
||||
}
|
||||
if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
|
||||
die("unable to create backing store for newly created file %s", path);
|
||||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
|
||||
die("unable to add cache entry for %s", path);
|
||||
}
|
||||
@@ -2398,6 +2452,13 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
|
||||
int fd;
|
||||
char *nbuf;
|
||||
|
||||
if (S_ISGITLINK(mode)) {
|
||||
struct stat st;
|
||||
if (!lstat(path, &st) && S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
return mkdir(path, 0777);
|
||||
}
|
||||
|
||||
if (has_symlinks && S_ISLNK(mode))
|
||||
/* Although buf:size is counted string, it also is NUL
|
||||
* terminated.
|
||||
@@ -2508,7 +2569,7 @@ static void write_out_one_result(struct patch *patch, int phase)
|
||||
* thing: remove the old, write the new
|
||||
*/
|
||||
if (phase == 0)
|
||||
remove_file(patch, 0);
|
||||
remove_file(patch, patch->is_rename);
|
||||
if (phase == 1)
|
||||
create_file(patch);
|
||||
}
|
||||
|
||||
@@ -44,38 +44,21 @@ struct bundle_header {
|
||||
struct ref_list references;
|
||||
};
|
||||
|
||||
/* this function returns the length of the string */
|
||||
static int read_string(int fd, char *buffer, int size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size - 1; i++) {
|
||||
ssize_t count = xread(fd, buffer + i, 1);
|
||||
if (count < 0)
|
||||
return error("Read error: %s", strerror(errno));
|
||||
if (count == 0) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
if (buffer[i] == '\n')
|
||||
break;
|
||||
}
|
||||
buffer[i + 1] = '\0';
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
/* returns an fd */
|
||||
static int read_header(const char *path, struct bundle_header *header) {
|
||||
char buffer[1024];
|
||||
int fd = open(path, O_RDONLY);
|
||||
int fd;
|
||||
long fpos;
|
||||
FILE *ffd = fopen(path, "rb");
|
||||
|
||||
if (fd < 0)
|
||||
if (!ffd)
|
||||
return error("could not open '%s'", path);
|
||||
if (read_string(fd, buffer, sizeof(buffer)) < 0 ||
|
||||
if (!fgets(buffer, sizeof(buffer), ffd) ||
|
||||
strcmp(buffer, bundle_signature)) {
|
||||
close(fd);
|
||||
fclose(ffd);
|
||||
return error("'%s' does not look like a v2 bundle file", path);
|
||||
}
|
||||
while (read_string(fd, buffer, sizeof(buffer)) > 0
|
||||
while (fgets(buffer, sizeof(buffer), ffd)
|
||||
&& buffer[0] != '\n') {
|
||||
int is_prereq = buffer[0] == '-';
|
||||
int offset = is_prereq ? 1 : 0;
|
||||
@@ -97,6 +80,12 @@ static int read_header(const char *path, struct bundle_header *header) {
|
||||
add_to_ref_list(sha1, isspace(delim) ?
|
||||
buffer + 41 + offset : "", list);
|
||||
}
|
||||
fpos = ftell(ffd);
|
||||
fclose(ffd);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return error("could not open '%s'", path);
|
||||
lseek(fd, fpos, SEEK_SET);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -200,18 +189,22 @@ static int list_heads(struct bundle_header *header, int argc, const char **argv)
|
||||
static int create_bundle(struct bundle_header *header, const char *path,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
static struct lock_file lock;
|
||||
int bundle_fd = -1;
|
||||
int bundle_to_stdout;
|
||||
const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
|
||||
const char **argv_pack = xmalloc(5 * sizeof(const char *));
|
||||
int i, ref_count = 0;
|
||||
char buffer[1024];
|
||||
struct rev_info revs;
|
||||
struct child_process rls;
|
||||
FILE *rls_fout;
|
||||
|
||||
bundle_fd = (!strcmp(path, "-") ? 1 :
|
||||
open(path, O_CREAT | O_EXCL | O_WRONLY, 0666));
|
||||
if (bundle_fd < 0)
|
||||
return error("Could not create '%s': %s", path, strerror(errno));
|
||||
bundle_to_stdout = !strcmp(path, "-");
|
||||
if (bundle_to_stdout)
|
||||
bundle_fd = 1;
|
||||
else
|
||||
bundle_fd = hold_lock_file_for_update(&lock, path, 1);
|
||||
|
||||
/* write signature */
|
||||
write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
|
||||
@@ -232,10 +225,11 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
rls.git_cmd = 1;
|
||||
if (start_command(&rls))
|
||||
return -1;
|
||||
while ((i = read_string(rls.out, buffer, sizeof(buffer))) > 0) {
|
||||
rls_fout = fdopen(rls.out, "r");
|
||||
while (fgets(buffer, sizeof(buffer), rls_fout)) {
|
||||
unsigned char sha1[20];
|
||||
if (buffer[0] == '-') {
|
||||
write_or_die(bundle_fd, buffer, i);
|
||||
write_or_die(bundle_fd, buffer, strlen(buffer));
|
||||
if (!get_sha1_hex(buffer + 1, sha1)) {
|
||||
struct object *object = parse_object(sha1);
|
||||
object->flags |= UNINTERESTING;
|
||||
@@ -246,6 +240,7 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
object->flags |= SHOWN;
|
||||
}
|
||||
}
|
||||
fclose(rls_fout);
|
||||
if (finish_command(&rls))
|
||||
return error("rev-list died");
|
||||
|
||||
@@ -267,12 +262,49 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
* Make sure the refs we wrote out is correct; --max-count and
|
||||
* other limiting options could have prevented all the tips
|
||||
* from getting output.
|
||||
*
|
||||
* Non commit objects such as tags and blobs do not have
|
||||
* this issue as they are not affected by those extra
|
||||
* constraints.
|
||||
*/
|
||||
if (!(e->item->flags & SHOWN)) {
|
||||
if (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) {
|
||||
warning("ref '%s' is excluded by the rev-list options",
|
||||
e->name);
|
||||
free(ref);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If you run "git bundle create bndl v1.0..v2.0", the
|
||||
* name of the positive ref is "v2.0" but that is the
|
||||
* commit that is referenced by the tag, and not the tag
|
||||
* itself.
|
||||
*/
|
||||
if (hashcmp(sha1, e->item->sha1)) {
|
||||
/*
|
||||
* Is this the positive end of a range expressed
|
||||
* in terms of a tag (e.g. v2.0 from the range
|
||||
* "v1.0..v2.0")?
|
||||
*/
|
||||
struct commit *one = lookup_commit_reference(sha1);
|
||||
struct object *obj;
|
||||
|
||||
if (e->item == &(one->object)) {
|
||||
/*
|
||||
* Need to include e->name as an
|
||||
* independent ref to the pack-objects
|
||||
* input, so that the tag is included
|
||||
* in the output; otherwise we would
|
||||
* end up triggering "empty bundle"
|
||||
* error.
|
||||
*/
|
||||
obj = parse_object(sha1);
|
||||
obj->flags |= SHOWN;
|
||||
add_pending_object(&revs, obj, e->name);
|
||||
}
|
||||
free(ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
ref_count++;
|
||||
write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40);
|
||||
write_or_die(bundle_fd, " ", 1);
|
||||
@@ -308,6 +340,9 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
}
|
||||
if (finish_command(&rls))
|
||||
return error ("pack-objects died");
|
||||
close(bundle_fd);
|
||||
if (!bundle_to_stdout)
|
||||
commit_lock_file(&lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "attr.h"
|
||||
#include "quote.h"
|
||||
|
||||
@@ -10,6 +11,10 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
|
||||
struct git_attr_check *check;
|
||||
int cnt, i, doubledash;
|
||||
|
||||
if (read_cache() < 0) {
|
||||
die("invalid cache");
|
||||
}
|
||||
|
||||
doubledash = -1;
|
||||
for (i = 1; doubledash < 0 && i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--"))
|
||||
|
||||
@@ -222,6 +222,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
prefix = setup_git_directory_gently(&nongit);
|
||||
git_config(git_diff_ui_config);
|
||||
init_revisions(&rev, prefix);
|
||||
rev.diffopt.skip_stat_unmatch = 1;
|
||||
|
||||
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
|
||||
argc = 0;
|
||||
@@ -235,6 +236,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
rev.diffopt.allow_external = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
|
||||
/* If the user asked for our exit code then don't start a
|
||||
* pager or we would end up reporting its exit code instead.
|
||||
*/
|
||||
if (!rev.diffopt.exit_with_status)
|
||||
setup_pager();
|
||||
|
||||
/* Do we have --cached and not have a pending object, then
|
||||
* default to HEAD by hand. Eek.
|
||||
*/
|
||||
@@ -338,5 +345,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
ent, ents);
|
||||
if (rev.diffopt.exit_with_status)
|
||||
result = rev.diffopt.has_changes;
|
||||
|
||||
if ((rev.diffopt.output_format & DIFF_FORMAT_PATCH)
|
||||
&& (1 < rev.diffopt.skip_stat_unmatch))
|
||||
printf("Warning: %d path%s touched but unmodified. "
|
||||
"Consider running git-status.\n",
|
||||
rev.diffopt.skip_stat_unmatch - 1,
|
||||
rev.diffopt.skip_stat_unmatch == 2 ? "" : "s");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -586,7 +586,7 @@ static off_t write_one(struct sha1file *f,
|
||||
static int open_object_dir_tmp(const char *path)
|
||||
{
|
||||
snprintf(tmpname, sizeof(tmpname), "%s/%s", get_object_directory(), path);
|
||||
return mkstemp(tmpname);
|
||||
return xmkstemp(tmpname);
|
||||
}
|
||||
|
||||
/* forward declaration for write_pack_file */
|
||||
@@ -612,8 +612,6 @@ static void write_pack_file(void)
|
||||
f = sha1fd(1, "<stdout>");
|
||||
} else {
|
||||
int fd = open_object_dir_tmp("tmp_pack_XXXXXX");
|
||||
if (fd < 0)
|
||||
die("unable to create %s: %s\n", tmpname, strerror(errno));
|
||||
pack_tmp_name = xstrdup(tmpname);
|
||||
f = sha1fd(fd, pack_tmp_name);
|
||||
}
|
||||
@@ -1275,9 +1273,8 @@ struct unpacked {
|
||||
unsigned depth;
|
||||
};
|
||||
|
||||
static int delta_cacheable(struct unpacked *trg, struct unpacked *src,
|
||||
unsigned long src_size, unsigned long trg_size,
|
||||
unsigned long delta_size)
|
||||
static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
|
||||
unsigned long delta_size)
|
||||
{
|
||||
if (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)
|
||||
return 0;
|
||||
@@ -1399,7 +1396,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
trg_entry->delta_size = delta_size;
|
||||
trg->depth = src->depth + 1;
|
||||
|
||||
if (delta_cacheable(src, trg, src_size, trg_size, delta_size)) {
|
||||
if (delta_cacheable(src_size, trg_size, delta_size)) {
|
||||
trg_entry->delta_data = xrealloc(delta_buf, delta_size);
|
||||
delta_cache_size += trg_entry->delta_size;
|
||||
} else
|
||||
|
||||
@@ -13,14 +13,20 @@
|
||||
#include "dir.h"
|
||||
#include "builtin.h"
|
||||
|
||||
static struct object_list *trees;
|
||||
#define MAX_TREES 8
|
||||
static int nr_trees;
|
||||
static struct tree *trees[MAX_TREES];
|
||||
|
||||
static int list_tree(unsigned char *sha1)
|
||||
{
|
||||
struct tree *tree = parse_tree_indirect(sha1);
|
||||
struct tree *tree;
|
||||
|
||||
if (nr_trees >= MAX_TREES)
|
||||
die("I cannot read more than %d trees", MAX_TREES);
|
||||
tree = parse_tree_indirect(sha1);
|
||||
if (!tree)
|
||||
return -1;
|
||||
object_list_append(&tree->object, &trees);
|
||||
trees[nr_trees++] = tree;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -76,11 +82,10 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
|
||||
|
||||
static void prime_cache_tree(void)
|
||||
{
|
||||
struct tree *tree = (struct tree *)trees->item;
|
||||
if (!tree)
|
||||
if (!nr_trees)
|
||||
return;
|
||||
active_cache_tree = cache_tree();
|
||||
prime_cache_tree_rec(active_cache_tree, tree);
|
||||
prime_cache_tree_rec(active_cache_tree, trees[0]);
|
||||
|
||||
}
|
||||
|
||||
@@ -92,6 +97,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
{
|
||||
int i, newfd, stage = 0;
|
||||
unsigned char sha1[20];
|
||||
struct tree_desc t[MAX_TREES];
|
||||
struct unpack_trees_options opts;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
@@ -258,7 +264,12 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
opts.head_idx = 1;
|
||||
}
|
||||
|
||||
unpack_trees(trees, &opts);
|
||||
for (i = 0; i < nr_trees; i++) {
|
||||
struct tree *tree = trees[i];
|
||||
parse_tree(tree);
|
||||
init_tree_desc(t+i, tree->buffer, tree->size);
|
||||
}
|
||||
unpack_trees(nr_trees, t, &opts);
|
||||
|
||||
/*
|
||||
* When reading only one tree (either the most basic form,
|
||||
@@ -266,7 +277,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
* valid cache-tree because the index must match exactly
|
||||
* what came from the tree.
|
||||
*/
|
||||
if (trees && trees->item && !opts.prefix && (!opts.merge || (stage == 2))) {
|
||||
if (nr_trees && !opts.prefix && (!opts.merge || (stage == 2))) {
|
||||
cache_tree_free(&active_cache_tree);
|
||||
prime_cache_tree();
|
||||
}
|
||||
|
||||
@@ -76,6 +76,11 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
char *buffer;
|
||||
unsigned long size;
|
||||
int strip_comments = 0;
|
||||
|
||||
if (argc > 1 && (!strcmp(argv[1], "-s") ||
|
||||
!strcmp(argv[1], "--strip-comments")))
|
||||
strip_comments = 1;
|
||||
|
||||
size = 1024;
|
||||
buffer = xmalloc(size);
|
||||
@@ -84,7 +89,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
|
||||
die("could not read the input");
|
||||
}
|
||||
|
||||
size = stripspace(buffer, size, 0);
|
||||
size = stripspace(buffer, size, strip_comments);
|
||||
write_or_die(1, buffer, size);
|
||||
if (size)
|
||||
putc('\n', stdout);
|
||||
|
||||
460
builtin-tag.c
Normal file
460
builtin-tag.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Builtin "git tag"
|
||||
*
|
||||
* Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,
|
||||
* Carlos Rica <jasampler@gmail.com>
|
||||
* Based on git-tag.sh and mktag.c by Linus Torvalds.
|
||||
*/
|
||||
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "refs.h"
|
||||
#include "tag.h"
|
||||
#include "run-command.h"
|
||||
|
||||
static const char builtin_tag_usage[] =
|
||||
"git-tag [-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>] <tagname> [<head>]";
|
||||
|
||||
static char signingkey[1000];
|
||||
|
||||
static void launch_editor(const char *path, char **buffer, unsigned long *len)
|
||||
{
|
||||
const char *editor, *terminal;
|
||||
struct child_process child;
|
||||
const char *args[3];
|
||||
int fd;
|
||||
|
||||
editor = getenv("GIT_EDITOR");
|
||||
if (!editor && editor_program)
|
||||
editor = editor_program;
|
||||
if (!editor)
|
||||
editor = getenv("VISUAL");
|
||||
if (!editor)
|
||||
editor = getenv("EDITOR");
|
||||
|
||||
terminal = getenv("TERM");
|
||||
if (!editor && (!terminal || !strcmp(terminal, "dumb"))) {
|
||||
fprintf(stderr,
|
||||
"Terminal is dumb but no VISUAL nor EDITOR defined.\n"
|
||||
"Please supply the message using either -m or -F option.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!editor)
|
||||
editor = "vi";
|
||||
|
||||
memset(&child, 0, sizeof(child));
|
||||
child.argv = args;
|
||||
args[0] = editor;
|
||||
args[1] = path;
|
||||
args[2] = NULL;
|
||||
|
||||
if (run_command(&child))
|
||||
die("There was a problem with the editor %s.", editor);
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
die("could not open '%s': %s", path, strerror(errno));
|
||||
if (read_fd(fd, buffer, len)) {
|
||||
free(*buffer);
|
||||
die("could not read message file '%s': %s",
|
||||
path, strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
struct tag_filter {
|
||||
const char *pattern;
|
||||
int lines;
|
||||
};
|
||||
|
||||
#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
|
||||
|
||||
static int show_reference(const char *refname, const unsigned char *sha1,
|
||||
int flag, void *cb_data)
|
||||
{
|
||||
struct tag_filter *filter = cb_data;
|
||||
|
||||
if (!fnmatch(filter->pattern, refname, 0)) {
|
||||
int i;
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
char *buf, *sp, *eol;
|
||||
size_t len;
|
||||
|
||||
if (!filter->lines) {
|
||||
printf("%s\n", refname);
|
||||
return 0;
|
||||
}
|
||||
printf("%-15s ", refname);
|
||||
|
||||
sp = buf = read_sha1_file(sha1, &type, &size);
|
||||
if (!buf)
|
||||
return 0;
|
||||
if (!size) {
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
/* skip header */
|
||||
while (sp + 1 < buf + size &&
|
||||
!(sp[0] == '\n' && sp[1] == '\n'))
|
||||
sp++;
|
||||
/* only take up to "lines" lines, and strip the signature */
|
||||
for (i = 0, sp += 2;
|
||||
i < filter->lines && sp < buf + size &&
|
||||
prefixcmp(sp, PGP_SIGNATURE "\n");
|
||||
i++) {
|
||||
if (i)
|
||||
printf("\n ");
|
||||
eol = memchr(sp, '\n', size - (sp - buf));
|
||||
len = eol ? eol - sp : size - (sp - buf);
|
||||
fwrite(sp, len, 1, stdout);
|
||||
if (!eol)
|
||||
break;
|
||||
sp = eol + 1;
|
||||
}
|
||||
putchar('\n');
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int list_tags(const char *pattern, int lines)
|
||||
{
|
||||
struct tag_filter filter;
|
||||
char *newpattern;
|
||||
|
||||
if (pattern == NULL)
|
||||
pattern = "";
|
||||
|
||||
/* prepend/append * to the shell pattern: */
|
||||
newpattern = xmalloc(strlen(pattern) + 3);
|
||||
sprintf(newpattern, "*%s*", pattern);
|
||||
|
||||
filter.pattern = newpattern;
|
||||
filter.lines = lines;
|
||||
|
||||
for_each_tag_ref(show_reference, (void *) &filter);
|
||||
|
||||
free(newpattern);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*each_tag_name_fn)(const char *name, const char *ref,
|
||||
const unsigned char *sha1);
|
||||
|
||||
static int for_each_tag_name(const char **argv, each_tag_name_fn fn)
|
||||
{
|
||||
const char **p;
|
||||
char ref[PATH_MAX];
|
||||
int had_error = 0;
|
||||
unsigned char sha1[20];
|
||||
|
||||
for (p = argv; *p; p++) {
|
||||
if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
|
||||
>= sizeof(ref)) {
|
||||
error("tag name too long: %.*s...", 50, *p);
|
||||
had_error = 1;
|
||||
continue;
|
||||
}
|
||||
if (!resolve_ref(ref, sha1, 1, NULL)) {
|
||||
error("tag '%s' not found.", *p);
|
||||
had_error = 1;
|
||||
continue;
|
||||
}
|
||||
if (fn(*p, ref, sha1))
|
||||
had_error = 1;
|
||||
}
|
||||
return had_error;
|
||||
}
|
||||
|
||||
static int delete_tag(const char *name, const char *ref,
|
||||
const unsigned char *sha1)
|
||||
{
|
||||
if (delete_ref(ref, sha1))
|
||||
return 1;
|
||||
printf("Deleted tag '%s'\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_tag(const char *name, const char *ref,
|
||||
const unsigned char *sha1)
|
||||
{
|
||||
const char *argv_verify_tag[] = {"git-verify-tag",
|
||||
"-v", "SHA1_HEX", NULL};
|
||||
argv_verify_tag[2] = sha1_to_hex(sha1);
|
||||
|
||||
if (run_command_v_opt(argv_verify_tag, 0))
|
||||
return error("could not verify the tag '%s'", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t do_sign(char *buffer, size_t size, size_t max)
|
||||
{
|
||||
struct child_process gpg;
|
||||
const char *args[4];
|
||||
char *bracket;
|
||||
int len;
|
||||
|
||||
if (!*signingkey) {
|
||||
if (strlcpy(signingkey, git_committer_info(1),
|
||||
sizeof(signingkey)) > sizeof(signingkey) - 1)
|
||||
return error("committer info too long.");
|
||||
bracket = strchr(signingkey, '>');
|
||||
if (bracket)
|
||||
bracket[1] = '\0';
|
||||
}
|
||||
|
||||
memset(&gpg, 0, sizeof(gpg));
|
||||
gpg.argv = args;
|
||||
gpg.in = -1;
|
||||
gpg.out = -1;
|
||||
args[0] = "gpg";
|
||||
args[1] = "-bsau";
|
||||
args[2] = signingkey;
|
||||
args[3] = NULL;
|
||||
|
||||
if (start_command(&gpg))
|
||||
return error("could not run gpg.");
|
||||
|
||||
write_or_die(gpg.in, buffer, size);
|
||||
close(gpg.in);
|
||||
gpg.close_in = 0;
|
||||
len = read_in_full(gpg.out, buffer + size, max - size);
|
||||
|
||||
finish_command(&gpg);
|
||||
|
||||
if (len == max - size)
|
||||
return error("could not read the entire signature from gpg.");
|
||||
|
||||
return size + len;
|
||||
}
|
||||
|
||||
static const char tag_template[] =
|
||||
"\n"
|
||||
"#\n"
|
||||
"# Write a tag message\n"
|
||||
"#\n";
|
||||
|
||||
static int git_tag_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "user.signingkey")) {
|
||||
if (!value)
|
||||
die("user.signingkey without value");
|
||||
if (strlcpy(signingkey, value, sizeof(signingkey))
|
||||
>= sizeof(signingkey))
|
||||
die("user.signingkey value too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
#define MAX_SIGNATURE_LENGTH 1024
|
||||
/* message must be NULL or allocated, it will be reallocated and freed */
|
||||
static void create_tag(const unsigned char *object, const char *tag,
|
||||
char *message, int sign, unsigned char *result)
|
||||
{
|
||||
enum object_type type;
|
||||
char header_buf[1024], *buffer = NULL;
|
||||
int header_len, max_size;
|
||||
unsigned long size = 0;
|
||||
|
||||
type = sha1_object_info(object, NULL);
|
||||
if (type <= OBJ_NONE)
|
||||
die("bad object type.");
|
||||
|
||||
header_len = snprintf(header_buf, sizeof(header_buf),
|
||||
"object %s\n"
|
||||
"type %s\n"
|
||||
"tag %s\n"
|
||||
"tagger %s\n\n",
|
||||
sha1_to_hex(object),
|
||||
typename(type),
|
||||
tag,
|
||||
git_committer_info(1));
|
||||
|
||||
if (header_len > sizeof(header_buf) - 1)
|
||||
die("tag header too big.");
|
||||
|
||||
if (!message) {
|
||||
char *path;
|
||||
int fd;
|
||||
|
||||
/* write the template message before editing: */
|
||||
path = xstrdup(git_path("TAG_EDITMSG"));
|
||||
fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (fd < 0)
|
||||
die("could not create file '%s': %s",
|
||||
path, strerror(errno));
|
||||
write_or_die(fd, tag_template, strlen(tag_template));
|
||||
close(fd);
|
||||
|
||||
launch_editor(path, &buffer, &size);
|
||||
|
||||
unlink(path);
|
||||
free(path);
|
||||
}
|
||||
else {
|
||||
buffer = message;
|
||||
size = strlen(message);
|
||||
}
|
||||
|
||||
size = stripspace(buffer, size, 1);
|
||||
|
||||
if (!message && !size)
|
||||
die("no tag message?");
|
||||
|
||||
/* insert the header and add the '\n' if needed: */
|
||||
max_size = header_len + size + (sign ? MAX_SIGNATURE_LENGTH : 0) + 1;
|
||||
buffer = xrealloc(buffer, max_size);
|
||||
if (size)
|
||||
buffer[size++] = '\n';
|
||||
memmove(buffer + header_len, buffer, size);
|
||||
memcpy(buffer, header_buf, header_len);
|
||||
size += header_len;
|
||||
|
||||
if (sign) {
|
||||
size = do_sign(buffer, size, max_size);
|
||||
if (size < 0)
|
||||
die("unable to sign the tag");
|
||||
}
|
||||
|
||||
if (write_sha1_file(buffer, size, tag_type, result) < 0)
|
||||
die("unable to write tag file");
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
unsigned char object[20], prev[20];
|
||||
int annotate = 0, sign = 0, force = 0, lines = 0;
|
||||
char *message = NULL;
|
||||
char ref[PATH_MAX];
|
||||
const char *object_ref, *tag;
|
||||
int i;
|
||||
struct ref_lock *lock;
|
||||
|
||||
git_config(git_tag_config);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
if (!strcmp(arg, "-a")) {
|
||||
annotate = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-s")) {
|
||||
annotate = 1;
|
||||
sign = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-f")) {
|
||||
force = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-n")) {
|
||||
if (i + 1 == argc || *argv[i + 1] == '-')
|
||||
/* no argument */
|
||||
lines = 1;
|
||||
else
|
||||
lines = isdigit(*argv[++i]) ?
|
||||
atoi(argv[i]) : 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-m")) {
|
||||
annotate = 1;
|
||||
i++;
|
||||
if (i == argc)
|
||||
die("option -m needs an argument.");
|
||||
if (message)
|
||||
die("only one -F or -m option is allowed.");
|
||||
message = xstrdup(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-F")) {
|
||||
unsigned long len;
|
||||
int fd;
|
||||
|
||||
annotate = 1;
|
||||
i++;
|
||||
if (i == argc)
|
||||
die("option -F needs an argument.");
|
||||
if (message)
|
||||
die("only one -F or -m option is allowed.");
|
||||
|
||||
if (!strcmp(argv[i], "-"))
|
||||
fd = 0;
|
||||
else {
|
||||
fd = open(argv[i], O_RDONLY);
|
||||
if (fd < 0)
|
||||
die("could not open '%s': %s",
|
||||
argv[i], strerror(errno));
|
||||
}
|
||||
len = 1024;
|
||||
message = xmalloc(len);
|
||||
if (read_fd(fd, &message, &len)) {
|
||||
free(message);
|
||||
die("cannot read %s", argv[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-u")) {
|
||||
annotate = 1;
|
||||
sign = 1;
|
||||
i++;
|
||||
if (i == argc)
|
||||
die("option -u needs an argument.");
|
||||
if (strlcpy(signingkey, argv[i], sizeof(signingkey))
|
||||
>= sizeof(signingkey))
|
||||
die("argument to option -u too long");
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-l"))
|
||||
return list_tags(argv[i + 1], lines);
|
||||
if (!strcmp(arg, "-d"))
|
||||
return for_each_tag_name(argv + i + 1, delete_tag);
|
||||
if (!strcmp(arg, "-v"))
|
||||
return for_each_tag_name(argv + i + 1, verify_tag);
|
||||
usage(builtin_tag_usage);
|
||||
}
|
||||
|
||||
if (i == argc) {
|
||||
if (annotate)
|
||||
usage(builtin_tag_usage);
|
||||
return list_tags(NULL, lines);
|
||||
}
|
||||
tag = argv[i++];
|
||||
|
||||
object_ref = i < argc ? argv[i] : "HEAD";
|
||||
if (i + 1 < argc)
|
||||
die("too many params");
|
||||
|
||||
if (get_sha1(object_ref, object))
|
||||
die("Failed to resolve '%s' as a valid ref.", object_ref);
|
||||
|
||||
if (snprintf(ref, sizeof(ref), "refs/tags/%s", tag) > sizeof(ref) - 1)
|
||||
die("tag name too long: %.*s...", 50, tag);
|
||||
if (check_ref_format(ref))
|
||||
die("'%s' is not a valid tag name.", tag);
|
||||
|
||||
if (!resolve_ref(ref, prev, 1, NULL))
|
||||
hashclr(prev);
|
||||
else if (!force)
|
||||
die("tag '%s' already exists", tag);
|
||||
|
||||
if (annotate)
|
||||
create_tag(object, tag, message, sign, object);
|
||||
|
||||
lock = lock_any_ref_for_update(ref, prev, 0);
|
||||
if (!lock)
|
||||
die("%s: cannot lock the ref", ref);
|
||||
if (write_ref_sha1(lock, object, NULL) < 0)
|
||||
die("%s: cannot update the ref", ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -86,9 +86,15 @@ static int process_lstat_error(const char *path, int err)
|
||||
|
||||
static int add_one_path(struct cache_entry *old, const char *path, int len, struct stat *st)
|
||||
{
|
||||
int option, size = cache_entry_size(len);
|
||||
struct cache_entry *ce = xcalloc(1, size);
|
||||
int option, size;
|
||||
struct cache_entry *ce;
|
||||
|
||||
/* Was the old index entry already up-to-date? */
|
||||
if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
|
||||
return 0;
|
||||
|
||||
size = cache_entry_size(len);
|
||||
ce = xcalloc(1, size);
|
||||
memcpy(ce->name, path, len);
|
||||
ce->ce_flags = htons(len);
|
||||
fill_stat_cache_info(ce, st);
|
||||
|
||||
110
builtin-verify-tag.c
Normal file
110
builtin-verify-tag.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Builtin "git verify-tag"
|
||||
*
|
||||
* Copyright (c) 2007 Carlos Rica <jasampler@gmail.com>
|
||||
*
|
||||
* Based on git-verify-tag.sh
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "tag.h"
|
||||
#include "run-command.h"
|
||||
#include <signal.h>
|
||||
|
||||
static const char builtin_verify_tag_usage[] =
|
||||
"git-verify-tag [-v|--verbose] <tag>...";
|
||||
|
||||
#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
|
||||
|
||||
static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
|
||||
{
|
||||
struct child_process gpg;
|
||||
const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
|
||||
char path[PATH_MAX], *eol;
|
||||
size_t len;
|
||||
int fd, ret;
|
||||
|
||||
fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
|
||||
if (fd < 0)
|
||||
return error("could not create temporary file '%s': %s",
|
||||
path, strerror(errno));
|
||||
if (write_in_full(fd, buf, size) < 0)
|
||||
return error("failed writing temporary file '%s': %s",
|
||||
path, strerror(errno));
|
||||
close(fd);
|
||||
|
||||
/* find the length without signature */
|
||||
len = 0;
|
||||
while (len < size && prefixcmp(buf + len, PGP_SIGNATURE "\n")) {
|
||||
eol = memchr(buf + len, '\n', size - len);
|
||||
len += eol ? eol - (buf + len) + 1 : size - len;
|
||||
}
|
||||
if (verbose)
|
||||
write_in_full(1, buf, len);
|
||||
|
||||
memset(&gpg, 0, sizeof(gpg));
|
||||
gpg.argv = args_gpg;
|
||||
gpg.in = -1;
|
||||
gpg.out = 1;
|
||||
args_gpg[2] = path;
|
||||
if (start_command(&gpg))
|
||||
return error("could not run gpg.");
|
||||
|
||||
write_in_full(gpg.in, buf, len);
|
||||
close(gpg.in);
|
||||
gpg.close_in = 0;
|
||||
ret = finish_command(&gpg);
|
||||
|
||||
unlink(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int verify_tag(const char *name, int verbose)
|
||||
{
|
||||
enum object_type type;
|
||||
unsigned char sha1[20];
|
||||
char *buf;
|
||||
unsigned long size;
|
||||
int ret;
|
||||
|
||||
if (get_sha1(name, sha1))
|
||||
return error("tag '%s' not found.", name);
|
||||
|
||||
type = sha1_object_info(sha1, NULL);
|
||||
if (type != OBJ_TAG)
|
||||
return error("%s: cannot verify a non-tag object of type %s.",
|
||||
name, typename(type));
|
||||
|
||||
buf = read_sha1_file(sha1, &type, &size);
|
||||
if (!buf)
|
||||
return error("%s: unable to read file.", name);
|
||||
|
||||
ret = run_gpg_verify(buf, size, verbose);
|
||||
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i = 1, verbose = 0, had_error = 0;
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
if (argc == 1)
|
||||
usage(builtin_verify_tag_usage);
|
||||
|
||||
if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
|
||||
verbose = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* sometimes the program was terminated because this signal
|
||||
* was received in the process of writing the gpg input: */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
while (i < argc)
|
||||
if (verify_tag(argv[i++], verbose))
|
||||
had_error = 1;
|
||||
return had_error;
|
||||
}
|
||||
@@ -70,12 +70,14 @@ extern int cmd_show(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_tag(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_version(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
|
||||
|
||||
7
cache.h
7
cache.h
@@ -173,7 +173,7 @@ extern struct index_state the_index;
|
||||
#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
|
||||
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
|
||||
#define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
|
||||
#define refresh_cache(flags) refresh_index(&the_index, flags)
|
||||
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
|
||||
#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really))
|
||||
#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really))
|
||||
#endif
|
||||
@@ -258,6 +258,7 @@ extern int index_name_pos(struct index_state *, const char *name, int namelen);
|
||||
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
|
||||
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
|
||||
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
|
||||
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
|
||||
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
|
||||
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
|
||||
extern int remove_index_entry_at(struct index_state *, int pos);
|
||||
@@ -277,7 +278,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
||||
#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
|
||||
#define REFRESH_QUIET 0x0004 /* be quiet about it */
|
||||
#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
|
||||
extern int refresh_index(struct index_state *, unsigned int flags);
|
||||
extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen);
|
||||
|
||||
struct lock_file {
|
||||
struct lock_file *next;
|
||||
@@ -574,6 +575,8 @@ extern char *pager_program;
|
||||
extern int pager_in_use;
|
||||
extern int pager_use_color;
|
||||
|
||||
extern char *editor_program;
|
||||
|
||||
/* base85 */
|
||||
int decode_85(char *dst, const char *line, int linelen);
|
||||
void encode_85(char *buf, const unsigned char *data, int bytes);
|
||||
|
||||
5
config.c
5
config.c
@@ -427,6 +427,11 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.editor")) {
|
||||
editor_program = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
14
connect.c
14
connect.c
@@ -146,6 +146,8 @@ static enum protocol get_protocol(const char *name)
|
||||
return PROTO_SSH;
|
||||
if (!strcmp(name, "ssh+git"))
|
||||
return PROTO_SSH;
|
||||
if (!strcmp(name, "file"))
|
||||
return PROTO_LOCAL;
|
||||
die("I don't handle protocol '%s'", name);
|
||||
}
|
||||
|
||||
@@ -515,14 +517,14 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
|
||||
end = host;
|
||||
|
||||
path = strchr(end, c);
|
||||
if (c == ':') {
|
||||
/* host must have at least 2 chars to catch DOS C:/path */
|
||||
if (path && path - end > 1) {
|
||||
/* host must have at least 2 chars to catch DOS C:/path */
|
||||
if (path && path - end > 1) {
|
||||
if (c == ':') {
|
||||
protocol = PROTO_SSH;
|
||||
*path++ = '\0';
|
||||
} else
|
||||
path = host;
|
||||
}
|
||||
}
|
||||
} else
|
||||
path = end;
|
||||
|
||||
if (!path || !*path)
|
||||
die("No path specified. See 'man git-pull' for valid url syntax");
|
||||
|
||||
@@ -972,6 +972,11 @@ _git_show ()
|
||||
__git_complete_file
|
||||
}
|
||||
|
||||
_git_stash ()
|
||||
{
|
||||
__gitcomp 'list show apply clear'
|
||||
}
|
||||
|
||||
_git ()
|
||||
{
|
||||
local i c=1 command __git_dir
|
||||
@@ -1028,6 +1033,7 @@ _git ()
|
||||
shortlog) _git_shortlog ;;
|
||||
show) _git_show ;;
|
||||
show-branch) _git_log ;;
|
||||
stash) _git_stash ;;
|
||||
whatchanged) _git_log ;;
|
||||
*) COMPREPLY=() ;;
|
||||
esac
|
||||
@@ -1073,6 +1079,7 @@ complete -o default -o nospace -F _git_remote git-remote
|
||||
complete -o default -o nospace -F _git_reset git-reset
|
||||
complete -o default -o nospace -F _git_shortlog git-shortlog
|
||||
complete -o default -o nospace -F _git_show git-show
|
||||
complete -o default -o nospace -F _git_stash git-stash
|
||||
complete -o default -o nospace -F _git_log git-show-branch
|
||||
complete -o default -o nospace -F _git_log git-whatchanged
|
||||
|
||||
|
||||
@@ -912,10 +912,12 @@ Return the list of files that haven't been handled."
|
||||
|
||||
(defun git-setup-diff-buffer (buffer)
|
||||
"Setup a buffer for displaying a diff."
|
||||
(with-current-buffer buffer
|
||||
(diff-mode)
|
||||
(goto-char (point-min))
|
||||
(setq buffer-read-only t))
|
||||
(let ((dir default-directory))
|
||||
(with-current-buffer buffer
|
||||
(diff-mode)
|
||||
(goto-char (point-min))
|
||||
(setq default-directory dir)
|
||||
(setq buffer-read-only t)))
|
||||
(display-buffer buffer)
|
||||
(shrink-window-if-larger-than-buffer))
|
||||
|
||||
@@ -965,7 +967,13 @@ Return the list of files that haven't been handled."
|
||||
(defun git-diff-file-idiff ()
|
||||
"Perform an interactive diff on the current file."
|
||||
(interactive)
|
||||
(error "Interactive diffs not implemented yet."))
|
||||
(let ((files (git-marked-files-state 'added 'deleted 'modified)))
|
||||
(unless (eq 1 (length files))
|
||||
(error "Cannot perform an interactive diff on multiple files."))
|
||||
(let* ((filename (car (git-get-filenames files)))
|
||||
(buff1 (find-file-noselect filename))
|
||||
(buff2 (git-run-command-buffer (concat filename ".~HEAD~") "cat-file" "blob" (concat "HEAD:" filename))))
|
||||
(ediff-buffers buff1 buff2))))
|
||||
|
||||
(defun git-log-file ()
|
||||
"Display a log of changes to the marked file(s)."
|
||||
|
||||
@@ -390,6 +390,30 @@ class P4Submit(Command):
|
||||
|
||||
return result
|
||||
|
||||
def prepareSubmitTemplate(self):
|
||||
# remove lines in the Files section that show changes to files outside the depot path we're committing into
|
||||
template = ""
|
||||
inFilesSection = False
|
||||
for line in read_pipe_lines("p4 change -o"):
|
||||
if inFilesSection:
|
||||
if line.startswith("\t"):
|
||||
# path starts and ends with a tab
|
||||
path = line[1:]
|
||||
lastTab = path.rfind("\t")
|
||||
if lastTab != -1:
|
||||
path = path[:lastTab]
|
||||
if not path.startswith(self.depotPath):
|
||||
continue
|
||||
else:
|
||||
inFilesSection = False
|
||||
else:
|
||||
if line.startswith("Files:"):
|
||||
inFilesSection = True
|
||||
|
||||
template += line
|
||||
|
||||
return template
|
||||
|
||||
def applyCommit(self, id):
|
||||
if self.directSubmit:
|
||||
print "Applying local change in working directory/index"
|
||||
@@ -467,7 +491,7 @@ class P4Submit(Command):
|
||||
logMessage = logMessage.replace("\n", "\r\n")
|
||||
logMessage = logMessage.strip()
|
||||
|
||||
template = read_pipe("p4 change -o")
|
||||
template = self.prepareSubmitTemplate()
|
||||
|
||||
if self.interactive:
|
||||
submitTemplate = self.prepareLogMessage(template, logMessage)
|
||||
@@ -558,24 +582,24 @@ class P4Submit(Command):
|
||||
return False
|
||||
|
||||
[upstream, settings] = findUpstreamBranchPoint()
|
||||
depotPath = settings['depot-paths'][0]
|
||||
self.depotPath = settings['depot-paths'][0]
|
||||
if len(self.origin) == 0:
|
||||
self.origin = upstream
|
||||
|
||||
if self.verbose:
|
||||
print "Origin branch is " + self.origin
|
||||
|
||||
if len(depotPath) == 0:
|
||||
if len(self.depotPath) == 0:
|
||||
print "Internal error: cannot locate perforce depot path from existing branches"
|
||||
sys.exit(128)
|
||||
|
||||
self.clientPath = p4Where(depotPath)
|
||||
self.clientPath = p4Where(self.depotPath)
|
||||
|
||||
if len(self.clientPath) == 0:
|
||||
print "Error: Cannot locate perforce checkout of %s in client view" % depotPath
|
||||
print "Error: Cannot locate perforce checkout of %s in client view" % self.depotPath
|
||||
sys.exit(128)
|
||||
|
||||
print "Perforce checkout for depot path %s located at %s" % (depotPath, self.clientPath)
|
||||
print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
|
||||
self.oldWorkingDirectory = os.getcwd()
|
||||
|
||||
if self.directSubmit:
|
||||
@@ -839,16 +863,20 @@ class P4Sync(Command):
|
||||
if file["action"] == "delete":
|
||||
self.gitStream.write("D %s\n" % relPath)
|
||||
else:
|
||||
mode = 644
|
||||
if file["type"].startswith("x"):
|
||||
mode = 755
|
||||
|
||||
data = file['data']
|
||||
|
||||
mode = "644"
|
||||
if file["type"].startswith("x"):
|
||||
mode = "755"
|
||||
elif file["type"] == "symlink":
|
||||
mode = "120000"
|
||||
# p4 print on a symlink contains "target\n", so strip it off
|
||||
data = data[:-1]
|
||||
|
||||
if self.isWindows and file["type"].endswith("text"):
|
||||
data = data.replace("\r\n", "\n")
|
||||
|
||||
self.gitStream.write("M %d inline %s\n" % (mode, relPath))
|
||||
self.gitStream.write("M %s inline %s\n" % (mode, relPath))
|
||||
self.gitStream.write("data %s\n" % len(data))
|
||||
self.gitStream.write(data)
|
||||
self.gitStream.write("\n")
|
||||
@@ -1294,7 +1322,7 @@ class P4Sync(Command):
|
||||
|
||||
for line in output:
|
||||
changeNum = line.split(" ")[1]
|
||||
changes.append(changeNum)
|
||||
changes.append(int(changeNum))
|
||||
|
||||
changes.sort()
|
||||
|
||||
|
||||
@@ -102,6 +102,8 @@ my ($this_user) = getpwuid $<; # REAL_USER_ID
|
||||
my $repository_name;
|
||||
my %user_committer;
|
||||
my @allow_rules;
|
||||
my @path_rules;
|
||||
my %diff_cache;
|
||||
|
||||
sub deny ($) {
|
||||
print STDERR "-Deny- $_[0]\n" if $debug;
|
||||
@@ -118,22 +120,36 @@ sub info ($) {
|
||||
print STDERR "-Info- $_[0]\n" if $debug;
|
||||
}
|
||||
|
||||
sub parse_config ($$) {
|
||||
my ($data, $fn) = @_;
|
||||
info "Loading $fn";
|
||||
open(I,'-|','git',"--git-dir=$acl_git",'cat-file','blob',$fn);
|
||||
sub git_value (@) {
|
||||
open(T,'-|','git',@_); local $_ = <T>; chop; close T; $_;
|
||||
}
|
||||
|
||||
sub match_string ($$) {
|
||||
my ($acl_n, $ref) = @_;
|
||||
($acl_n eq $ref)
|
||||
|| ($acl_n =~ m,/$, && substr($ref,0,length $acl_n) eq $acl_n)
|
||||
|| ($acl_n =~ m,^\^, && $ref =~ m:$acl_n:);
|
||||
}
|
||||
|
||||
sub parse_config ($$$$) {
|
||||
my $data = shift;
|
||||
local $ENV{GIT_DIR} = shift;
|
||||
my $br = shift;
|
||||
my $fn = shift;
|
||||
info "Loading $br:$fn";
|
||||
open(I,'-|','git','cat-file','blob',"$br:$fn");
|
||||
my $section = '';
|
||||
while (<I>) {
|
||||
chomp;
|
||||
if (/^\s*$/ || /^\s*#/) {
|
||||
} elsif (/^\[([a-z]+)\]$/i) {
|
||||
$section = $1;
|
||||
$section = lc $1;
|
||||
} elsif (/^\[([a-z]+)\s+"(.*)"\]$/i) {
|
||||
$section = "$1.$2";
|
||||
$section = join('.',lc $1,$2);
|
||||
} elsif (/^\s*([a-z][a-z0-9]+)\s*=\s*(.*?)\s*$/i) {
|
||||
push @{$data->{"$section.$1"}}, $2;
|
||||
push @{$data->{join('.',$section,lc $1)}}, $2;
|
||||
} else {
|
||||
deny "bad config file line $. in $fn";
|
||||
deny "bad config file line $. in $br:$fn";
|
||||
}
|
||||
}
|
||||
close I;
|
||||
@@ -202,9 +218,40 @@ sub check_committers (@) {
|
||||
}
|
||||
}
|
||||
|
||||
sub git_value (@) {
|
||||
open(T,'-|','git',@_); local $_ = <T>; chop; close T;
|
||||
$_;
|
||||
sub load_diff ($) {
|
||||
my $base = shift;
|
||||
my $d = $diff_cache{$base};
|
||||
unless ($d) {
|
||||
local $/ = "\0";
|
||||
my %this_diff;
|
||||
if ($base =~ /^0{40}$/) {
|
||||
open(T,'-|','git','ls-tree',
|
||||
'-r','--name-only','-z',
|
||||
$new) or return undef;
|
||||
while (<T>) {
|
||||
chop;
|
||||
$this_diff{$_} = 'A';
|
||||
}
|
||||
close T or return undef;
|
||||
} else {
|
||||
open(T,'-|','git','diff-tree',
|
||||
'-r','--name-status','-z',
|
||||
$base,$new) or return undef;
|
||||
while (<T>) {
|
||||
my $op = $_;
|
||||
chop $op;
|
||||
|
||||
my $path = <T>;
|
||||
chop $path;
|
||||
|
||||
$this_diff{$path} = $op;
|
||||
}
|
||||
close T or return undef;
|
||||
}
|
||||
$d = \%this_diff;
|
||||
$diff_cache{$base} = $d;
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
|
||||
deny "No GIT_DIR inherited from caller" unless $git_dir;
|
||||
@@ -231,14 +278,52 @@ $op = 'U' if ($op eq 'R'
|
||||
&& $ref =~ m,^heads/,
|
||||
&& $old eq git_value('merge-base',$old,$new));
|
||||
|
||||
# Load the user's ACL file.
|
||||
# Load the user's ACL file. Expand groups (user.memberof) one level.
|
||||
{
|
||||
my %data = ('user.committer' => []);
|
||||
parse_config(\%data, "$acl_branch:users/$this_user.acl");
|
||||
parse_config(\%data,$acl_git,$acl_branch,"external/$repository_name.acl");
|
||||
|
||||
%data = (
|
||||
'user.committer' => $data{'user.committer'},
|
||||
'user.memberof' => [],
|
||||
);
|
||||
parse_config(\%data,$acl_git,$acl_branch,"users/$this_user.acl");
|
||||
|
||||
%user_committer = map {$_ => $_} @{$data{'user.committer'}};
|
||||
my $rules = $data{"repository.$repository_name.allow"} || [];
|
||||
my $rule_key = "repository.$repository_name.allow";
|
||||
my $rules = $data{$rule_key} || [];
|
||||
|
||||
foreach my $group (@{$data{'user.memberof'}}) {
|
||||
my %g;
|
||||
parse_config(\%g,$acl_git,$acl_branch,"groups/$group.acl");
|
||||
my $group_rules = $g{$rule_key};
|
||||
push @$rules, @$group_rules if $group_rules;
|
||||
}
|
||||
|
||||
RULE:
|
||||
foreach (@$rules) {
|
||||
if (/^([CDRU ]+)\s+for\s+([^\s]+)$/) {
|
||||
while (/\${user\.([a-z][a-zA-Z0-9]+)}/) {
|
||||
my $k = lc $1;
|
||||
my $v = $data{"user.$k"};
|
||||
next RULE unless defined $v;
|
||||
next RULE if @$v != 1;
|
||||
next RULE unless defined $v->[0];
|
||||
s/\${user\.$k}/$v->[0]/g;
|
||||
}
|
||||
|
||||
if (/^([AMD ]+)\s+of\s+([^\s]+)\s+for\s+([^\s]+)\s+diff\s+([^\s]+)$/) {
|
||||
my ($ops, $pth, $ref, $bst) = ($1, $2, $3, $4);
|
||||
$ops =~ s/ //g;
|
||||
$pth =~ s/\\\\/\\/g;
|
||||
$ref =~ s/\\\\/\\/g;
|
||||
push @path_rules, [$ops, $pth, $ref, $bst];
|
||||
} elsif (/^([AMD ]+)\s+of\s+([^\s]+)\s+for\s+([^\s]+)$/) {
|
||||
my ($ops, $pth, $ref) = ($1, $2, $3);
|
||||
$ops =~ s/ //g;
|
||||
$pth =~ s/\\\\/\\/g;
|
||||
$ref =~ s/\\\\/\\/g;
|
||||
push @path_rules, [$ops, $pth, $ref, $old];
|
||||
} elsif (/^([CDRU ]+)\s+for\s+([^\s]+)$/) {
|
||||
my $ops = $1;
|
||||
my $ref = $2;
|
||||
$ops =~ s/ //g;
|
||||
@@ -272,13 +357,65 @@ foreach my $acl_entry (@allow_rules) {
|
||||
next unless $acl_ops =~ /^[CDRU]+$/; # Uhh.... shouldn't happen.
|
||||
next unless $acl_n;
|
||||
next unless $op =~ /^[$acl_ops]$/;
|
||||
next unless match_string $acl_n, $ref;
|
||||
|
||||
grant "Allowed by: $acl_ops for $acl_n"
|
||||
if (
|
||||
($acl_n eq $ref)
|
||||
|| ($acl_n =~ m,/$, && substr($ref,0,length $acl_n) eq $acl_n)
|
||||
|| ($acl_n =~ m,^\^, && $ref =~ m:$acl_n:)
|
||||
);
|
||||
# Don't test path rules on branch deletes.
|
||||
#
|
||||
grant "Allowed by: $acl_ops for $acl_n" if $op eq 'D';
|
||||
|
||||
# Aggregate matching path rules; allow if there aren't
|
||||
# any matching this ref.
|
||||
#
|
||||
my %pr;
|
||||
foreach my $p_entry (@path_rules) {
|
||||
my ($p_ops, $p_n, $p_ref, $p_bst) = @$p_entry;
|
||||
next unless $p_ref;
|
||||
push @{$pr{$p_bst}}, $p_entry if match_string $p_ref, $ref;
|
||||
}
|
||||
grant "Allowed by: $acl_ops for $acl_n" unless %pr;
|
||||
|
||||
# Allow only if all changes against a single base are
|
||||
# allowed by file path rules.
|
||||
#
|
||||
my @bad;
|
||||
foreach my $p_bst (keys %pr) {
|
||||
my $diff_ref = load_diff $p_bst;
|
||||
deny "Cannot difference trees." unless ref $diff_ref;
|
||||
|
||||
my %fd = %$diff_ref;
|
||||
foreach my $p_entry (@{$pr{$p_bst}}) {
|
||||
my ($p_ops, $p_n, $p_ref, $p_bst) = @$p_entry;
|
||||
next unless $p_ops =~ /^[AMD]+$/;
|
||||
next unless $p_n;
|
||||
|
||||
foreach my $f_n (keys %fd) {
|
||||
my $f_op = $fd{$f_n};
|
||||
next unless $f_op;
|
||||
next unless $f_op =~ /^[$p_ops]$/;
|
||||
delete $fd{$f_n} if match_string $p_n, $f_n;
|
||||
}
|
||||
last unless %fd;
|
||||
}
|
||||
|
||||
if (%fd) {
|
||||
push @bad, [$p_bst, \%fd];
|
||||
} else {
|
||||
# All changes relative to $p_bst were allowed.
|
||||
#
|
||||
grant "Allowed by: $acl_ops for $acl_n diff $p_bst";
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $bad_ref (@bad) {
|
||||
my ($p_bst, $fd) = @$bad_ref;
|
||||
print STDERR "\n";
|
||||
print STDERR "Not allowed to make the following changes:\n";
|
||||
print STDERR "(base: $p_bst)\n";
|
||||
foreach my $f_n (sort keys %$fd) {
|
||||
print STDERR " $fd->{$f_n} $f_n\n";
|
||||
}
|
||||
}
|
||||
deny "You are not permitted to $op $ref";
|
||||
}
|
||||
close A;
|
||||
deny "You are not permitted to $op $ref";
|
||||
|
||||
21
contrib/patches/docbook-xsl-manpages-charmap.patch
Normal file
21
contrib/patches/docbook-xsl-manpages-charmap.patch
Normal file
@@ -0,0 +1,21 @@
|
||||
From: Ismail Dönmez <ismail@pardus.org.tr>
|
||||
|
||||
Trying to build the documentation with docbook-xsl 1.73 may result in
|
||||
the following error. This patch fixes it.
|
||||
|
||||
$ xmlto -m callouts.xsl man git-add.xml
|
||||
runtime error: file
|
||||
file:///usr/share/sgml/docbook/xsl-stylesheets-1.73.0/manpages/other.xsl line
|
||||
129 element call-template
|
||||
The called template 'read-character-map' was not found.
|
||||
|
||||
--- docbook-xsl-1.73.0/manpages/docbook.xsl.manpages-charmap 2007-07-23 16:24:23.000000000 +0100
|
||||
+++ docbook-xsl-1.73.0/manpages/docbook.xsl 2007-07-23 16:25:16.000000000 +0100
|
||||
@@ -37,6 +37,7 @@
|
||||
<xsl:include href="lists.xsl"/>
|
||||
<xsl:include href="endnotes.xsl"/>
|
||||
<xsl:include href="table.xsl"/>
|
||||
+ <xsl:include href="../common/charmap.xsl"/>
|
||||
|
||||
<!-- * we rename the following just to avoid using params with "man" -->
|
||||
<!-- * prefixes in the table.xsl stylesheet (because that stylesheet -->
|
||||
@@ -189,6 +189,7 @@ static int handle_diff_files_args(struct rev_info *revs,
|
||||
!strcmp(argv[1], "--no-index")) {
|
||||
revs->max_count = -2;
|
||||
revs->diffopt.exit_with_status = 1;
|
||||
revs->diffopt.no_index = 1;
|
||||
}
|
||||
else if (!strcmp(argv[1], "-q"))
|
||||
*silent = 1;
|
||||
@@ -204,8 +205,10 @@ static int handle_diff_files_args(struct rev_info *revs,
|
||||
*/
|
||||
read_cache();
|
||||
if (!is_in_index(revs->diffopt.paths[0]) ||
|
||||
!is_in_index(revs->diffopt.paths[1]))
|
||||
!is_in_index(revs->diffopt.paths[1])) {
|
||||
revs->max_count = -2;
|
||||
revs->diffopt.no_index = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -293,6 +296,7 @@ int setup_diff_no_index(struct rev_info *revs,
|
||||
else
|
||||
revs->diffopt.paths = argv + argc - 2;
|
||||
revs->diffopt.nr_paths = 2;
|
||||
revs->diffopt.no_index = 1;
|
||||
revs->max_count = -2;
|
||||
return 0;
|
||||
}
|
||||
@@ -304,7 +308,7 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
|
||||
if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
|
||||
return -1;
|
||||
|
||||
if (revs->max_count == -2) {
|
||||
if (revs->diffopt.no_index) {
|
||||
if (revs->diffopt.nr_paths != 2)
|
||||
return error("need two files/directories with --no-index");
|
||||
if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
|
||||
|
||||
53
diff.c
53
diff.c
@@ -3138,11 +3138,64 @@ static void diffcore_apply_filter(const char *filter)
|
||||
*q = outq;
|
||||
}
|
||||
|
||||
static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
|
||||
{
|
||||
int i;
|
||||
struct diff_queue_struct *q = &diff_queued_diff;
|
||||
struct diff_queue_struct outq;
|
||||
outq.queue = NULL;
|
||||
outq.nr = outq.alloc = 0;
|
||||
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
struct diff_filepair *p = q->queue[i];
|
||||
|
||||
/*
|
||||
* 1. Entries that come from stat info dirtyness
|
||||
* always have both sides (iow, not create/delete),
|
||||
* one side of the object name is unknown, with
|
||||
* the same mode and size. Keep the ones that
|
||||
* do not match these criteria. They have real
|
||||
* differences.
|
||||
*
|
||||
* 2. At this point, the file is known to be modified,
|
||||
* with the same mode and size, and the object
|
||||
* name of one side is unknown. Need to inspect
|
||||
* the identical contents.
|
||||
*/
|
||||
if (!DIFF_FILE_VALID(p->one) || /* (1) */
|
||||
!DIFF_FILE_VALID(p->two) ||
|
||||
(p->one->sha1_valid && p->two->sha1_valid) ||
|
||||
(p->one->mode != p->two->mode) ||
|
||||
diff_populate_filespec(p->one, 1) ||
|
||||
diff_populate_filespec(p->two, 1) ||
|
||||
(p->one->size != p->two->size) ||
|
||||
|
||||
diff_populate_filespec(p->one, 0) || /* (2) */
|
||||
diff_populate_filespec(p->two, 0) ||
|
||||
memcmp(p->one->data, p->two->data, p->one->size))
|
||||
diff_q(&outq, p);
|
||||
else {
|
||||
/*
|
||||
* The caller can subtract 1 from skip_stat_unmatch
|
||||
* to determine how many paths were dirty only
|
||||
* due to stat info mismatch.
|
||||
*/
|
||||
if (!diffopt->no_index)
|
||||
diffopt->skip_stat_unmatch++;
|
||||
diff_free_filepair(p);
|
||||
}
|
||||
}
|
||||
free(q->queue);
|
||||
*q = outq;
|
||||
}
|
||||
|
||||
void diffcore_std(struct diff_options *options)
|
||||
{
|
||||
if (options->quiet)
|
||||
return;
|
||||
|
||||
if (options->skip_stat_unmatch && !options->find_copies_harder)
|
||||
diffcore_skip_stat_unmatch(options);
|
||||
if (options->break_opt != -1)
|
||||
diffcore_break(options->break_opt);
|
||||
if (options->detect_rename)
|
||||
|
||||
2
diff.h
2
diff.h
@@ -60,11 +60,13 @@ struct diff_options {
|
||||
color_diff_words:1,
|
||||
has_changes:1,
|
||||
quiet:1,
|
||||
no_index:1,
|
||||
allow_external:1,
|
||||
exit_with_status:1;
|
||||
int context;
|
||||
int break_opt;
|
||||
int detect_rename;
|
||||
int skip_stat_unmatch;
|
||||
int line_termination;
|
||||
int output_format;
|
||||
int pickaxe_opts;
|
||||
|
||||
19
entry.c
19
entry.c
@@ -112,6 +112,16 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
|
||||
if (!new)
|
||||
return error("git-checkout-index: unable to read sha1 file of %s (%s)",
|
||||
path, sha1_to_hex(ce->sha1));
|
||||
|
||||
/*
|
||||
* Convert from git internal format to working tree format
|
||||
*/
|
||||
buf = convert_to_working_tree(ce->name, new, &size);
|
||||
if (buf) {
|
||||
free(new);
|
||||
new = buf;
|
||||
}
|
||||
|
||||
if (to_tempfile) {
|
||||
strcpy(path, ".merge_file_XXXXXX");
|
||||
fd = mkstemp(path);
|
||||
@@ -123,15 +133,6 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
|
||||
path, strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from git internal format to working tree format
|
||||
*/
|
||||
buf = convert_to_working_tree(ce->name, new, &size);
|
||||
if (buf) {
|
||||
free(new);
|
||||
new = buf;
|
||||
}
|
||||
|
||||
wrote = write_in_full(fd, new, size);
|
||||
close(fd);
|
||||
free(new);
|
||||
|
||||
@@ -33,6 +33,7 @@ size_t delta_base_cache_limit = 16 * 1024 * 1024;
|
||||
char *pager_program;
|
||||
int pager_in_use;
|
||||
int pager_use_color = 1;
|
||||
char *editor_program;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
|
||||
/* This is set by setup_git_dir_gently() and/or git_default_config() */
|
||||
|
||||
@@ -663,9 +663,7 @@ static void start_packfile(void)
|
||||
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_pack_XXXXXX", get_object_directory());
|
||||
pack_fd = mkstemp(tmpfile);
|
||||
if (pack_fd < 0)
|
||||
die("Can't create %s: %s", tmpfile, strerror(errno));
|
||||
pack_fd = xmkstemp(tmpfile);
|
||||
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
|
||||
strcpy(p->pack_name, tmpfile);
|
||||
p->pack_fd = pack_fd;
|
||||
@@ -727,9 +725,7 @@ static char *create_index(void)
|
||||
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_idx_XXXXXX", get_object_directory());
|
||||
idx_fd = mkstemp(tmpfile);
|
||||
if (idx_fd < 0)
|
||||
die("Can't create %s: %s", tmpfile, strerror(errno));
|
||||
idx_fd = xmkstemp(tmpfile);
|
||||
f = sha1fd(idx_fd, tmpfile);
|
||||
sha1write(f, array, 256 * sizeof(int));
|
||||
SHA1_Init(&ctx);
|
||||
|
||||
@@ -103,7 +103,8 @@ It does not apply to blobs recorded in its index."
|
||||
}
|
||||
|
||||
prec=4
|
||||
dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= resolvemsg=
|
||||
dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary=
|
||||
resolvemsg= resume=
|
||||
git_apply_opt=
|
||||
|
||||
while case "$#" in 0) break;; esac
|
||||
|
||||
71
git-clone.sh
71
git-clone.sh
@@ -87,7 +87,7 @@ Perhaps git-update-server-info needs to be run there?"
|
||||
|
||||
quiet=
|
||||
local=no
|
||||
use_local=no
|
||||
use_local_hardlink=yes
|
||||
local_shared=no
|
||||
unset template
|
||||
no_checkout=
|
||||
@@ -108,9 +108,13 @@ while
|
||||
no_checkout=yes ;;
|
||||
*,--na|*,--nak|*,--nake|*,--naked|\
|
||||
*,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
|
||||
*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
|
||||
*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
|
||||
use_local_hardlink=yes ;;
|
||||
*,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
|
||||
*,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
|
||||
use_local_hardlink=no ;;
|
||||
*,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
|
||||
local_shared=yes; use_local=yes ;;
|
||||
local_shared=yes; ;;
|
||||
1,--template) usage ;;
|
||||
*,--template)
|
||||
shift; template="--template=$1" ;;
|
||||
@@ -211,7 +215,12 @@ else
|
||||
GIT_DIR="$D/.git"
|
||||
fi &&
|
||||
export GIT_DIR &&
|
||||
git-init $quiet ${template+"$template"} || usage
|
||||
GIT_CONFIG="$GIT_DIR/config" git-init $quiet ${template+"$template"} || usage
|
||||
|
||||
if test -n "$bare"
|
||||
then
|
||||
GIT_CONFIG="$GIT_DIR/config" git config core.bare true
|
||||
fi
|
||||
|
||||
if test -n "$reference"
|
||||
then
|
||||
@@ -249,34 +258,36 @@ fi
|
||||
rm -f "$GIT_DIR/CLONE_HEAD"
|
||||
|
||||
# We do local magic only when the user tells us to.
|
||||
case "$local,$use_local" in
|
||||
yes,yes)
|
||||
case "$local" in
|
||||
yes)
|
||||
( cd "$repo/objects" ) ||
|
||||
die "-l flag seen but repository '$repo' is not local."
|
||||
die "cannot chdir to local '$repo/objects'."
|
||||
|
||||
case "$local_shared" in
|
||||
no)
|
||||
# See if we can hardlink and drop "l" if not.
|
||||
sample_file=$(cd "$repo" && \
|
||||
/usr/bin/find objects -type f -print | sed -e 1q)
|
||||
|
||||
# objects directory should not be empty since we are cloning!
|
||||
test -f "$repo/$sample_file" || exit
|
||||
|
||||
l=
|
||||
if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
|
||||
then
|
||||
l=l
|
||||
fi &&
|
||||
rm -f "$GIT_DIR/objects/sample" &&
|
||||
cd "$repo" &&
|
||||
/usr/bin/find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
|
||||
;;
|
||||
yes)
|
||||
mkdir -p "$GIT_DIR/objects/info"
|
||||
echo "$repo/objects" >> "$GIT_DIR/objects/info/alternates"
|
||||
;;
|
||||
esac
|
||||
if test "$local_shared" = yes
|
||||
then
|
||||
mkdir -p "$GIT_DIR/objects/info"
|
||||
echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates"
|
||||
else
|
||||
l= &&
|
||||
if test "$use_local_hardlink" = yes
|
||||
then
|
||||
# See if we can hardlink and drop "l" if not.
|
||||
sample_file=$(cd "$repo" && \
|
||||
/usr/bin/find objects -type f -print | sed -e 1q)
|
||||
# objects directory should not be empty because
|
||||
# we are cloning!
|
||||
test -f "$repo/$sample_file" || exit
|
||||
if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
|
||||
then
|
||||
rm -f "$GIT_DIR/objects/sample"
|
||||
l=l
|
||||
else
|
||||
echo >&2 "Warning: -l asked but cannot hardlink to $repo"
|
||||
fi
|
||||
fi &&
|
||||
cd "$repo" &&
|
||||
/usr/bin/find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
|
||||
fi
|
||||
git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -314,6 +314,16 @@ static inline FILE *xfdopen(int fd, const char *mode)
|
||||
return stream;
|
||||
}
|
||||
|
||||
static inline int xmkstemp(char *template)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = mkstemp(template);
|
||||
if (fd < 0)
|
||||
die("Unable to create temporary file: %s", strerror(errno));
|
||||
return fd;
|
||||
}
|
||||
|
||||
static inline size_t xsize_t(off_t len)
|
||||
{
|
||||
return (size_t)len;
|
||||
|
||||
@@ -1196,6 +1196,7 @@ sub req_ci
|
||||
$log->info("Lockless commit start, basing commit on '$tmpdir', index file is '$file_index'");
|
||||
|
||||
$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
|
||||
$ENV{GIT_WORK_TREE} = ".";
|
||||
$ENV{GIT_INDEX_FILE} = $file_index;
|
||||
|
||||
# Remember where the head was at the beginning.
|
||||
@@ -1721,6 +1722,7 @@ sub req_annotate
|
||||
$log->info("Temp checkoutdir creation successful, basing annotate session work on '$tmpdir', index file is '$file_index'");
|
||||
|
||||
$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
|
||||
$ENV{GIT_WORK_TREE} = ".";
|
||||
$ENV{GIT_INDEX_FILE} = $file_index;
|
||||
|
||||
chdir $tmpdir;
|
||||
|
||||
@@ -170,13 +170,6 @@ do
|
||||
esac
|
||||
done < "$tempdir"/backup-refs
|
||||
|
||||
case "$GIT_DIR" in
|
||||
/*)
|
||||
;;
|
||||
*)
|
||||
GIT_DIR="$(pwd)/../../$GIT_DIR"
|
||||
;;
|
||||
esac
|
||||
export GIT_DIR GIT_WORK_TREE=.
|
||||
|
||||
# These refs should be updated if their heads were rewritten
|
||||
|
||||
@@ -8,13 +8,7 @@ USAGE='[--start] [--stop] [--restart]
|
||||
|
||||
. git-sh-setup
|
||||
|
||||
case "$GIT_DIR" in
|
||||
/*)
|
||||
fqgitdir="$GIT_DIR" ;;
|
||||
*)
|
||||
fqgitdir="$PWD/$GIT_DIR" ;;
|
||||
esac
|
||||
|
||||
fqgitdir="$GIT_DIR"
|
||||
local="`git config --bool --get instaweb.local`"
|
||||
httpd="`git config --get instaweb.httpd`"
|
||||
browser="`git config --get instaweb.browser`"
|
||||
|
||||
@@ -137,7 +137,7 @@ my $compose_filename = ".msg.$$";
|
||||
|
||||
# Variables we fill in automatically, or via prompting:
|
||||
my (@to,@cc,@initial_cc,@bcclist,@xh,
|
||||
$initial_reply_to,$initial_subject,@files,$from,$compose,$time);
|
||||
$initial_reply_to,$initial_subject,@files,$author,$sender,$compose,$time);
|
||||
|
||||
my $smtp_server;
|
||||
my $envelope_sender;
|
||||
@@ -179,7 +179,7 @@ if (!@bcclist or !$bcclist[0]) {
|
||||
# Begin by accumulating all the variables (defined above), that we will end up
|
||||
# needing, first, from the command line:
|
||||
|
||||
my $rc = GetOptions("from=s" => \$from,
|
||||
my $rc = GetOptions("sender|from=s" => \$sender,
|
||||
"in-reply-to=s" => \$initial_reply_to,
|
||||
"subject=s" => \$initial_subject,
|
||||
"to=s" => \@to,
|
||||
@@ -216,8 +216,8 @@ foreach my $entry (@bcclist) {
|
||||
|
||||
# Now, let's fill any that aren't set in with defaults:
|
||||
|
||||
my ($author) = $repo->ident_person('author');
|
||||
my ($committer) = $repo->ident_person('committer');
|
||||
my ($repoauthor) = $repo->ident_person('author');
|
||||
my ($repocommitter) = $repo->ident_person('committer');
|
||||
|
||||
my %aliases;
|
||||
my @alias_files = $repo->config('sendemail.aliasesfile');
|
||||
@@ -254,17 +254,17 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
|
||||
}
|
||||
}
|
||||
|
||||
($from) = expand_aliases($from) if defined $from;
|
||||
($sender) = expand_aliases($sender) if defined $sender;
|
||||
|
||||
my $prompting = 0;
|
||||
if (!defined $from) {
|
||||
$from = $author || $committer;
|
||||
if (!defined $sender) {
|
||||
$sender = $repoauthor || $repocommitter;
|
||||
do {
|
||||
$_ = $term->readline("Who should the emails appear to be from? [$from] ");
|
||||
$_ = $term->readline("Who should the emails appear to be from? [$sender] ");
|
||||
} while (!defined $_);
|
||||
|
||||
$from = $_ if ($_);
|
||||
print "Emails will be sent from: ", $from, "\n";
|
||||
$sender = $_ if ($_);
|
||||
print "Emails will be sent from: ", $sender, "\n";
|
||||
$prompting++;
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ sub expand_aliases {
|
||||
}
|
||||
|
||||
@to = expand_aliases(@to);
|
||||
@to = (map { sanitize_address_rfc822($_) } @to);
|
||||
@to = (map { sanitize_address($_) } @to);
|
||||
@initial_cc = expand_aliases(@initial_cc);
|
||||
@bcclist = expand_aliases(@bcclist);
|
||||
|
||||
@@ -330,7 +330,7 @@ if ($compose) {
|
||||
# effort to have it be unique
|
||||
open(C,">",$compose_filename)
|
||||
or die "Failed to open for writing $compose_filename: $!";
|
||||
print C "From $from # This line is ignored.\n";
|
||||
print C "From $sender # This line is ignored.\n";
|
||||
printf C "Subject: %s\n\n", $initial_subject;
|
||||
printf C <<EOT;
|
||||
GIT: Please enter your email below.
|
||||
@@ -408,8 +408,8 @@ sub extract_valid_address {
|
||||
# check for a local address:
|
||||
return $address if ($address =~ /^($local_part_regexp)$/);
|
||||
|
||||
$address =~ s/^\s*<(.*)>\s*$/$1/;
|
||||
if ($have_email_valid) {
|
||||
$address =~ s/^\s*<(.*)>\s*$/$1/;
|
||||
return scalar Email::Valid->address($address);
|
||||
} else {
|
||||
# less robust/correct than the monster regexp in Email::Valid,
|
||||
@@ -433,11 +433,11 @@ sub make_message_id
|
||||
my $date = time;
|
||||
my $pseudo_rand = int (rand(4200));
|
||||
my $du_part;
|
||||
for ($from, $committer, $author) {
|
||||
$du_part = extract_valid_address($_);
|
||||
last if ($du_part ne '');
|
||||
for ($sender, $repocommitter, $repoauthor) {
|
||||
$du_part = extract_valid_address(sanitize_address($_));
|
||||
last if (defined $du_part and $du_part ne '');
|
||||
}
|
||||
if ($du_part eq '') {
|
||||
if (not defined $du_part or $du_part eq '') {
|
||||
use Sys::Hostname qw();
|
||||
$du_part = 'user@' . Sys::Hostname::hostname();
|
||||
}
|
||||
@@ -459,22 +459,41 @@ sub unquote_rfc2047 {
|
||||
return "$_";
|
||||
}
|
||||
|
||||
# If an address contains a . in the name portion, the name must be quoted.
|
||||
sub sanitize_address_rfc822
|
||||
# use the simplest quoting being able to handle the recipient
|
||||
sub sanitize_address
|
||||
{
|
||||
my ($recipient) = @_;
|
||||
my ($recipient_name) = ($recipient =~ /^(.*?)\s+</);
|
||||
if ($recipient_name && $recipient_name =~ /\./ && $recipient_name !~ /^".*"$/) {
|
||||
my ($name, $addr) = ($recipient =~ /^(.*?)(\s+<.*)/);
|
||||
$recipient = "\"$name\"$addr";
|
||||
my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
|
||||
|
||||
if (not $recipient_name) {
|
||||
return "$recipient";
|
||||
}
|
||||
return $recipient;
|
||||
|
||||
# if recipient_name is already quoted, do nothing
|
||||
if ($recipient_name =~ /^(".*"|=\?utf-8\?q\?.*\?=)$/) {
|
||||
return $recipient;
|
||||
}
|
||||
|
||||
# rfc2047 is needed if a non-ascii char is included
|
||||
if ($recipient_name =~ /[^[:ascii:]]/) {
|
||||
$recipient_name =~ s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
|
||||
$recipient_name =~ s/(.*)/=\?utf-8\?q\?$1\?=/;
|
||||
}
|
||||
|
||||
# double quotes are needed if specials or CTLs are included
|
||||
elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
|
||||
$recipient_name =~ s/(["\\\r])/\\$1/;
|
||||
$recipient_name = "\"$recipient_name\"";
|
||||
}
|
||||
|
||||
return "$recipient_name $recipient_addr";
|
||||
|
||||
}
|
||||
|
||||
sub send_message
|
||||
{
|
||||
my @recipients = unique_email_list(@to);
|
||||
@cc = (map { sanitize_address_rfc822($_) } @cc);
|
||||
@cc = (map { sanitize_address($_) } @cc);
|
||||
my $to = join (",\n\t", @recipients);
|
||||
@recipients = unique_email_list(@recipients,@cc,@bcclist);
|
||||
@recipients = (map { extract_valid_address($_) } @recipients);
|
||||
@@ -489,10 +508,10 @@ sub send_message
|
||||
if ($cc ne '') {
|
||||
$ccline = "\nCc: $cc";
|
||||
}
|
||||
$from = sanitize_address_rfc822($from);
|
||||
my $sanitized_sender = sanitize_address($sender);
|
||||
make_message_id();
|
||||
|
||||
my $header = "From: $from
|
||||
my $header = "From: $sanitized_sender
|
||||
To: $to${ccline}
|
||||
Subject: $subject
|
||||
Date: $date
|
||||
@@ -509,7 +528,7 @@ X-Mailer: git-send-email $gitversion
|
||||
}
|
||||
|
||||
my @sendmail_parameters = ('-i', @recipients);
|
||||
my $raw_from = $from;
|
||||
my $raw_from = $sanitized_sender;
|
||||
$raw_from = $envelope_sender if (defined $envelope_sender);
|
||||
$raw_from = extract_valid_address($raw_from);
|
||||
unshift (@sendmail_parameters,
|
||||
@@ -546,7 +565,7 @@ X-Mailer: git-send-email $gitversion
|
||||
} else {
|
||||
print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
|
||||
}
|
||||
print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
|
||||
print "From: $sanitized_sender\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
|
||||
if ($smtp) {
|
||||
print "Result: ", $smtp->code, ' ',
|
||||
($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
|
||||
@@ -563,7 +582,7 @@ $subject = $initial_subject;
|
||||
foreach my $t (@files) {
|
||||
open(F,"<",$t) or die "can't open file $t";
|
||||
|
||||
my $author_not_sender = undef;
|
||||
my $author = undef;
|
||||
@cc = @initial_cc;
|
||||
@xh = ();
|
||||
my $input_format = undef;
|
||||
@@ -585,12 +604,11 @@ foreach my $t (@files) {
|
||||
$subject = $1;
|
||||
|
||||
} elsif (/^(Cc|From):\s+(.*)$/) {
|
||||
if (unquote_rfc2047($2) eq $from) {
|
||||
$from = $2;
|
||||
if (unquote_rfc2047($2) eq $sender) {
|
||||
next if ($suppress_from);
|
||||
}
|
||||
elsif ($1 eq 'From') {
|
||||
$author_not_sender = $2;
|
||||
$author = unquote_rfc2047($2);
|
||||
}
|
||||
printf("(mbox) Adding cc: %s from line '%s'\n",
|
||||
$2, $_) unless $quiet;
|
||||
@@ -634,9 +652,8 @@ foreach my $t (@files) {
|
||||
}
|
||||
}
|
||||
close F;
|
||||
if (defined $author_not_sender) {
|
||||
$author_not_sender = unquote_rfc2047($author_not_sender);
|
||||
$message = "From: $author_not_sender\n\n$message";
|
||||
if (defined $author) {
|
||||
$message = "From: $author\n\n$message";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -116,6 +116,16 @@ then
|
||||
exit $exit
|
||||
}
|
||||
else
|
||||
GIT_DIR=$(git rev-parse --git-dir) || exit
|
||||
GIT_DIR=$(git rev-parse --git-dir) || {
|
||||
exit=$?
|
||||
echo >&2 "Failed to find a valid git directory."
|
||||
exit $exit
|
||||
}
|
||||
fi
|
||||
|
||||
test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
|
||||
echo >&2 "Unable to determine absolute path of git directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
||||
|
||||
24
git-svn.perl
24
git-svn.perl
@@ -3501,11 +3501,17 @@ sub log_use_color {
|
||||
sub git_svn_log_cmd {
|
||||
my ($r_min, $r_max, @args) = @_;
|
||||
my $head = 'HEAD';
|
||||
my (@files, @log_opts);
|
||||
foreach my $x (@args) {
|
||||
last if $x eq '--';
|
||||
next unless ::verify_ref("$x^0");
|
||||
$head = $x;
|
||||
last;
|
||||
if ($x eq '--' || @files) {
|
||||
push @files, $x;
|
||||
} else {
|
||||
if (::verify_ref("$x^0")) {
|
||||
$head = $x;
|
||||
} else {
|
||||
push @log_opts, $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
|
||||
@@ -3515,13 +3521,13 @@ sub git_svn_log_cmd {
|
||||
push @cmd, '-r' unless $non_recursive;
|
||||
push @cmd, qw/--raw --name-status/ if $verbose;
|
||||
push @cmd, '--color' if log_use_color();
|
||||
return @cmd unless defined $r_max;
|
||||
if ($r_max == $r_min) {
|
||||
push @cmd, @log_opts;
|
||||
if (defined $r_max && $r_max == $r_min) {
|
||||
push @cmd, '--max-count=1';
|
||||
if (my $c = $gs->rev_db_get($r_max)) {
|
||||
push @cmd, $c;
|
||||
}
|
||||
} else {
|
||||
} elsif (defined $r_max) {
|
||||
my ($c_min, $c_max);
|
||||
$c_max = $gs->rev_db_get($r_max);
|
||||
$c_min = $gs->rev_db_get($r_min);
|
||||
@@ -3537,7 +3543,7 @@ sub git_svn_log_cmd {
|
||||
push @cmd, $c_min;
|
||||
}
|
||||
}
|
||||
return @cmd;
|
||||
return (@cmd, @files);
|
||||
}
|
||||
|
||||
# adapted from pager.c
|
||||
@@ -3702,7 +3708,7 @@ sub cmd_show_log {
|
||||
}
|
||||
|
||||
config_pager();
|
||||
@args = (git_svn_log_cmd($r_min, $r_max, @args), @args);
|
||||
@args = git_svn_log_cmd($r_min, $r_max, @args);
|
||||
my $log = command_output_pipe(@args);
|
||||
run_pager();
|
||||
my (@k, $c, $d, $stat);
|
||||
|
||||
@@ -49,7 +49,7 @@ getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:R:uv") or usage();
|
||||
usage if $opt_h;
|
||||
|
||||
my $tag_name = $opt_t || "tags";
|
||||
my $trunk_name = $opt_T || "trunk";
|
||||
my $trunk_name = defined $opt_T ? $opt_T : "trunk";
|
||||
my $branch_name = $opt_b || "branches";
|
||||
my $project_name = $opt_P || "";
|
||||
$project_name = "/" . $project_name if ($project_name);
|
||||
|
||||
7
git.c
7
git.c
@@ -319,7 +319,8 @@ static void handle_internal_command(int argc, const char **argv)
|
||||
{ "branch", cmd_branch, RUN_SETUP },
|
||||
{ "bundle", cmd_bundle },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index,
|
||||
RUN_SETUP | NEED_WORK_TREE},
|
||||
{ "check-ref-format", cmd_check_ref_format },
|
||||
{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "cherry", cmd_cherry, RUN_SETUP },
|
||||
@@ -328,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv)
|
||||
{ "config", cmd_config },
|
||||
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
||||
{ "describe", cmd_describe, RUN_SETUP },
|
||||
{ "diff", cmd_diff, USE_PAGER },
|
||||
{ "diff", cmd_diff },
|
||||
{ "diff-files", cmd_diff_files },
|
||||
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
||||
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
|
||||
@@ -372,11 +373,13 @@ static void handle_internal_command(int argc, const char **argv)
|
||||
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
||||
{ "stripspace", cmd_stripspace },
|
||||
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
||||
{ "tag", cmd_tag, RUN_SETUP },
|
||||
{ "tar-tree", cmd_tar_tree },
|
||||
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
||||
{ "update-index", cmd_update_index, RUN_SETUP },
|
||||
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
||||
{ "upload-archive", cmd_upload_archive },
|
||||
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
||||
{ "version", cmd_version },
|
||||
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||
|
||||
128
gitk
128
gitk
@@ -296,7 +296,7 @@ proc readcommit {id} {
|
||||
|
||||
proc updatecommits {} {
|
||||
global viewdata curview phase displayorder
|
||||
global children commitrow selectedline thickerline
|
||||
global children commitrow selectedline thickerline showneartags
|
||||
|
||||
if {$phase ne {}} {
|
||||
stop_rev_list
|
||||
@@ -313,7 +313,9 @@ proc updatecommits {} {
|
||||
catch {unset viewdata($n)}
|
||||
readrefs
|
||||
changedrefs
|
||||
regetallcommits
|
||||
if {$showneartags} {
|
||||
getallcommits
|
||||
}
|
||||
showview $n
|
||||
}
|
||||
|
||||
@@ -427,7 +429,7 @@ proc readrefs {} {
|
||||
lappend idotherrefs($id) $name
|
||||
}
|
||||
}
|
||||
close $refd
|
||||
catch {close $refd}
|
||||
set mainhead {}
|
||||
set mainheadid {}
|
||||
catch {
|
||||
@@ -823,8 +825,13 @@ proc makewindow {} {
|
||||
pack .ctop -fill both -expand 1
|
||||
bindall <1> {selcanvline %W %x %y}
|
||||
#bindall <B1-Motion> {selcanvline %W %x %y}
|
||||
bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
|
||||
bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
|
||||
if {[tk windowingsystem] == "win32"} {
|
||||
bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D }
|
||||
bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break }
|
||||
} else {
|
||||
bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
|
||||
bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
|
||||
}
|
||||
bindall <2> "canvscan mark %W %x %y"
|
||||
bindall <B2-Motion> "canvscan dragto %W %x %y"
|
||||
bindkey <Home> selfirstline
|
||||
@@ -879,6 +886,7 @@ proc makewindow {} {
|
||||
bind $cflist <1> {sel_flist %W %x %y; break}
|
||||
bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
|
||||
bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
|
||||
bind $cflist <Button-3> {pop_flist_menu %W %X %Y %x %y}
|
||||
|
||||
set maincursor [. cget -cursor]
|
||||
set textcursor [$ctext cget -cursor]
|
||||
@@ -916,6 +924,32 @@ proc makewindow {} {
|
||||
-command cobranch
|
||||
$headctxmenu add command -label "Remove this branch" \
|
||||
-command rmbranch
|
||||
|
||||
global flist_menu
|
||||
set flist_menu .flistctxmenu
|
||||
menu $flist_menu -tearoff 0
|
||||
$flist_menu add command -label "Highlight this too" \
|
||||
-command {flist_hl 0}
|
||||
$flist_menu add command -label "Highlight this only" \
|
||||
-command {flist_hl 1}
|
||||
}
|
||||
|
||||
# Windows sends all mouse wheel events to the current focused window, not
|
||||
# the one where the mouse hovers, so bind those events here and redirect
|
||||
# to the correct window
|
||||
proc windows_mousewheel_redirector {W X Y D} {
|
||||
global canv canv2 canv3
|
||||
set w [winfo containing -displayof $W $X $Y]
|
||||
if {$w ne ""} {
|
||||
set u [expr {$D < 0 ? 5 : -5}]
|
||||
if {$w == $canv || $w == $canv2 || $w == $canv3} {
|
||||
allcanvs yview scroll $u units
|
||||
} else {
|
||||
catch {
|
||||
$w yview scroll $u units
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# mouse-2 makes all windows scan vertically, but only the one
|
||||
@@ -955,8 +989,8 @@ proc bindkey {ev script} {
|
||||
# set the focus back to the toplevel for any click outside
|
||||
# the entry widgets
|
||||
proc click {w} {
|
||||
global entries
|
||||
foreach e $entries {
|
||||
global ctext entries
|
||||
foreach e [concat $entries $ctext] {
|
||||
if {$w == $e} return
|
||||
}
|
||||
focus .
|
||||
@@ -1500,6 +1534,33 @@ proc sel_flist {w x y} {
|
||||
}
|
||||
}
|
||||
|
||||
proc pop_flist_menu {w X Y x y} {
|
||||
global ctext cflist cmitmode flist_menu flist_menu_file
|
||||
global treediffs diffids
|
||||
|
||||
set l [lindex [split [$w index "@$x,$y"] "."] 0]
|
||||
if {$l <= 1} return
|
||||
if {$cmitmode eq "tree"} {
|
||||
set e [linetoelt $l]
|
||||
if {[string index $e end] eq "/"} return
|
||||
} else {
|
||||
set e [lindex $treediffs($diffids) [expr {$l-2}]]
|
||||
}
|
||||
set flist_menu_file $e
|
||||
tk_popup $flist_menu $X $Y
|
||||
}
|
||||
|
||||
proc flist_hl {only} {
|
||||
global flist_menu_file highlight_files
|
||||
|
||||
set x [shellquote $flist_menu_file]
|
||||
if {$only || $highlight_files eq {}} {
|
||||
set highlight_files $x
|
||||
} else {
|
||||
append highlight_files " " $x
|
||||
}
|
||||
}
|
||||
|
||||
# Functions for adding and removing shell-type quoting
|
||||
|
||||
proc shellquote {str} {
|
||||
@@ -2837,17 +2898,12 @@ proc layoutrows {row endrow last} {
|
||||
set offs [lindex $rowoffsets $row]
|
||||
while {$row < $endrow} {
|
||||
set id [lindex $displayorder $row]
|
||||
set oldolds {}
|
||||
set newolds {}
|
||||
set nev [expr {[llength $idlist] - $maxwidth + 1}]
|
||||
foreach p [lindex $parentlist $row] {
|
||||
if {![info exists idinlist($p)]} {
|
||||
lappend newolds $p
|
||||
} elseif {!$idinlist($p)} {
|
||||
lappend oldolds $p
|
||||
if {![info exists idinlist($p)] || !$idinlist($p)} {
|
||||
incr nev
|
||||
}
|
||||
}
|
||||
set nev [expr {[llength $idlist] + [llength $newolds]
|
||||
+ [llength $oldolds] - $maxwidth + 1}]
|
||||
if {$nev > 0} {
|
||||
if {!$last &&
|
||||
$row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
|
||||
@@ -2866,12 +2922,22 @@ proc layoutrows {row endrow last} {
|
||||
if {[incr nev -1] <= 0} break
|
||||
continue
|
||||
}
|
||||
set rowchk($id) [expr {$row + $r}]
|
||||
set rowchk($i) [expr {$row + $r}]
|
||||
}
|
||||
}
|
||||
lset rowidlist $row $idlist
|
||||
lset rowoffsets $row $offs
|
||||
}
|
||||
set oldolds {}
|
||||
set newolds {}
|
||||
foreach p [lindex $parentlist $row] {
|
||||
if {![info exists idinlist($p)]} {
|
||||
lappend newolds $p
|
||||
} elseif {!$idinlist($p)} {
|
||||
lappend oldolds $p
|
||||
}
|
||||
set idinlist($p) 1
|
||||
}
|
||||
set col [lsearch -exact $idlist $id]
|
||||
if {$col < 0} {
|
||||
set col [llength $idlist]
|
||||
@@ -2917,12 +2983,10 @@ proc layoutrows {row endrow last} {
|
||||
lset offs $col {}
|
||||
}
|
||||
foreach i $newolds {
|
||||
set idinlist($i) 1
|
||||
set idrowranges($i) $id
|
||||
}
|
||||
incr col $l
|
||||
foreach oid $oldolds {
|
||||
set idinlist($oid) 1
|
||||
set idlist [linsert $idlist $col $oid]
|
||||
set offs [linsert $offs $col $o]
|
||||
makeuparrow $oid $col $row $o
|
||||
@@ -2963,7 +3027,7 @@ proc layouttail {} {
|
||||
set col [expr {[llength $idlist] - 1}]
|
||||
set id [lindex $idlist $col]
|
||||
addextraid $id $row
|
||||
unset idinlist($id)
|
||||
catch {unset idinlist($id)}
|
||||
lappend idrowranges($id) $id
|
||||
lappend rowrangelist $idrowranges($id)
|
||||
unset idrowranges($id)
|
||||
@@ -4566,6 +4630,7 @@ proc sellastline {} {
|
||||
|
||||
proc selnextline {dir} {
|
||||
global selectedline
|
||||
focus .
|
||||
if {![info exists selectedline]} return
|
||||
set l [expr {$selectedline + $dir}]
|
||||
unmarkmatches
|
||||
@@ -4646,6 +4711,7 @@ proc godo {elt} {
|
||||
|
||||
proc goback {} {
|
||||
global history historyindex
|
||||
focus .
|
||||
|
||||
if {$historyindex > 1} {
|
||||
incr historyindex -1
|
||||
@@ -4659,6 +4725,7 @@ proc goback {} {
|
||||
|
||||
proc goforw {} {
|
||||
global history historyindex
|
||||
focus .
|
||||
|
||||
if {$historyindex < [llength $history]} {
|
||||
set cmd [lindex $history $historyindex]
|
||||
@@ -6135,17 +6202,13 @@ proc rmbranch {} {
|
||||
proc getallcommits {} {
|
||||
global allcommits allids nbmp nextarc seeds
|
||||
|
||||
set allids {}
|
||||
set nbmp 0
|
||||
set nextarc 0
|
||||
set allcommits 0
|
||||
set seeds {}
|
||||
regetallcommits
|
||||
}
|
||||
|
||||
# Called when the graph might have changed
|
||||
proc regetallcommits {} {
|
||||
global allcommits seeds
|
||||
if {![info exists allcommits]} {
|
||||
set allids {}
|
||||
set nbmp 0
|
||||
set nextarc 0
|
||||
set allcommits 0
|
||||
set seeds {}
|
||||
}
|
||||
|
||||
set cmd [concat | git rev-list --all --parents]
|
||||
foreach id $seeds {
|
||||
@@ -7576,7 +7639,10 @@ catch {source ~/.gitk}
|
||||
font create optionfont -family sans-serif -size -12
|
||||
|
||||
# check that we can find a .git directory somewhere...
|
||||
set gitdir [gitdir]
|
||||
if {[catch {set gitdir [gitdir]}]} {
|
||||
show_error {} . "Cannot find a git repository here."
|
||||
exit 1
|
||||
}
|
||||
if {![file isdirectory $gitdir]} {
|
||||
show_error {} . "Cannot find the git directory \"$gitdir\"."
|
||||
exit 1
|
||||
|
||||
@@ -5366,7 +5366,7 @@ sub git_feed {
|
||||
|
||||
# log/feed of current (HEAD) branch, log of given branch, history of file/directory
|
||||
my $head = $hash || 'HEAD';
|
||||
my @commitlist = parse_commits($head, 150);
|
||||
my @commitlist = parse_commits($head, 150, 0, undef, $file_name);
|
||||
|
||||
my %latest_commit;
|
||||
my %latest_date;
|
||||
|
||||
8
ident.c
8
ident.c
@@ -191,11 +191,11 @@ static const char *env_hint =
|
||||
"\n"
|
||||
"Run\n"
|
||||
"\n"
|
||||
" git config user.email \"you@email.com\"\n"
|
||||
" git config user.name \"Your Name\"\n"
|
||||
" git config --global user.email \"you@email.com\"\n"
|
||||
" git config --global user.name \"Your Name\"\n"
|
||||
"\n"
|
||||
"To set the identity in this repository.\n"
|
||||
"Add --global to set your account\'s default\n"
|
||||
"to set your account\'s default identity.\n"
|
||||
"Omit --global to set the identity only in this repository.\n"
|
||||
"\n";
|
||||
|
||||
const char *fmt_ident(const char *name, const char *email,
|
||||
|
||||
@@ -114,7 +114,7 @@ static const char *open_pack_file(const char *pack_name)
|
||||
static char tmpfile[PATH_MAX];
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_pack_XXXXXX", get_object_directory());
|
||||
output_fd = mkstemp(tmpfile);
|
||||
output_fd = xmkstemp(tmpfile);
|
||||
pack_name = xstrdup(tmpfile);
|
||||
} else
|
||||
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
|
||||
|
||||
@@ -295,6 +295,9 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
if (opt->add_signoff)
|
||||
len = append_signoff(&msgbuf, &msgbuf_len, len,
|
||||
opt->add_signoff);
|
||||
if (opt->show_log_size)
|
||||
printf("log size %i\n", len);
|
||||
|
||||
printf("%s%s%s", msgbuf, extra, sep);
|
||||
free(msgbuf);
|
||||
}
|
||||
|
||||
@@ -216,13 +216,19 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
|
||||
*/
|
||||
static int index_only = 0;
|
||||
|
||||
static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
|
||||
{
|
||||
parse_tree(tree);
|
||||
init_tree_desc(desc, tree->buffer, tree->size);
|
||||
}
|
||||
|
||||
static int git_merge_trees(int index_only,
|
||||
struct tree *common,
|
||||
struct tree *head,
|
||||
struct tree *merge)
|
||||
{
|
||||
int rc;
|
||||
struct object_list *trees = NULL;
|
||||
struct tree_desc t[3];
|
||||
struct unpack_trees_options opts;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
@@ -234,11 +240,11 @@ static int git_merge_trees(int index_only,
|
||||
opts.head_idx = 2;
|
||||
opts.fn = threeway_merge;
|
||||
|
||||
object_list_append(&common->object, &trees);
|
||||
object_list_append(&head->object, &trees);
|
||||
object_list_append(&merge->object, &trees);
|
||||
init_tree_desc_from_tree(t+0, common);
|
||||
init_tree_desc_from_tree(t+1, head);
|
||||
init_tree_desc_from_tree(t+2, merge);
|
||||
|
||||
rc = unpack_trees(trees, &opts);
|
||||
rc = unpack_trees(3, t, &opts);
|
||||
cache_tree_free(&active_cache_tree);
|
||||
return rc;
|
||||
}
|
||||
@@ -671,6 +677,26 @@ struct ll_merge_driver {
|
||||
/*
|
||||
* Built-in low-levels
|
||||
*/
|
||||
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
|
||||
const char *path_unused,
|
||||
mmfile_t *orig,
|
||||
mmfile_t *src1, const char *name1,
|
||||
mmfile_t *src2, const char *name2,
|
||||
mmbuffer_t *result)
|
||||
{
|
||||
/*
|
||||
* The tentative merge result is "ours" for the final round,
|
||||
* or common ancestor for an internal merge. Still return
|
||||
* "conflicted merge" status.
|
||||
*/
|
||||
mmfile_t *stolen = index_only ? orig : src1;
|
||||
|
||||
result->ptr = stolen->ptr;
|
||||
result->size = stolen->size;
|
||||
stolen->ptr = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
|
||||
const char *path_unused,
|
||||
mmfile_t *orig,
|
||||
@@ -681,10 +707,15 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
|
||||
xpparam_t xpp;
|
||||
|
||||
if (buffer_is_binary(orig->ptr, orig->size) ||
|
||||
buffer_is_binary(src1->ptr, src1->size) ||
|
||||
buffer_is_binary(src2->ptr, src2->size))
|
||||
return error("Cannot merge binary files: %s vs. %s\n",
|
||||
buffer_is_binary(src1->ptr, src1->size) ||
|
||||
buffer_is_binary(src2->ptr, src2->size)) {
|
||||
warning("Cannot merge binary files: %s vs. %s\n",
|
||||
name1, name2);
|
||||
return ll_binary_merge(drv_unused, path_unused,
|
||||
orig, src1, name1,
|
||||
src2, name2,
|
||||
result);
|
||||
}
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
return xdl_merge(orig,
|
||||
@@ -737,26 +768,6 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
|
||||
const char *path_unused,
|
||||
mmfile_t *orig,
|
||||
mmfile_t *src1, const char *name1,
|
||||
mmfile_t *src2, const char *name2,
|
||||
mmbuffer_t *result)
|
||||
{
|
||||
/*
|
||||
* The tentative merge result is "ours" for the final round,
|
||||
* or common ancestor for an internal merge. Still return
|
||||
* "conflicted merge" status.
|
||||
*/
|
||||
mmfile_t *stolen = index_only ? orig : src1;
|
||||
|
||||
result->ptr = stolen->ptr;
|
||||
result->size = stolen->size;
|
||||
stolen->ptr = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LL_BINARY_MERGE 0
|
||||
#define LL_TEXT_MERGE 1
|
||||
#define LL_UNION_MERGE 2
|
||||
@@ -771,9 +782,7 @@ static void create_temp(mmfile_t *src, char *path)
|
||||
int fd;
|
||||
|
||||
strcpy(path, ".merge_file_XXXXXX");
|
||||
fd = mkstemp(path);
|
||||
if (fd < 0)
|
||||
die("unable to create temp-file");
|
||||
fd = xmkstemp(path);
|
||||
if (write_in_full(fd, src->ptr, src->size) != src->size)
|
||||
die("unable to write temp-file");
|
||||
close(fd);
|
||||
|
||||
@@ -45,7 +45,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
|
||||
static char tmpfile[PATH_MAX];
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_idx_XXXXXX", get_object_directory());
|
||||
fd = mkstemp(tmpfile);
|
||||
fd = xmkstemp(tmpfile);
|
||||
index_name = xstrdup(tmpfile);
|
||||
} else {
|
||||
unlink(index_name);
|
||||
|
||||
5
pager.c
5
pager.c
@@ -44,8 +44,11 @@ void setup_pager(void)
|
||||
|
||||
if (!isatty(1))
|
||||
return;
|
||||
if (!pager)
|
||||
if (!pager) {
|
||||
if (!pager_program)
|
||||
git_config(git_default_config);
|
||||
pager = pager_program;
|
||||
}
|
||||
if (!pager)
|
||||
pager = getenv("PAGER");
|
||||
if (!pager)
|
||||
|
||||
14
path-list.c
14
path-list.c
@@ -76,16 +76,18 @@ struct path_list_item *path_list_lookup(const char *path, struct path_list *list
|
||||
return list->items + i;
|
||||
}
|
||||
|
||||
void path_list_clear(struct path_list *list, int free_items)
|
||||
void path_list_clear(struct path_list *list, int free_util)
|
||||
{
|
||||
if (list->items) {
|
||||
int i;
|
||||
if (free_items)
|
||||
for (i = 0; i < list->nr; i++) {
|
||||
if (list->strdup_paths)
|
||||
free(list->items[i].path);
|
||||
if (list->strdup_paths) {
|
||||
for (i = 0; i < list->nr; i++)
|
||||
free(list->items[i].path);
|
||||
}
|
||||
if (free_util) {
|
||||
for (i = 0; i < list->nr; i++)
|
||||
free(list->items[i].util);
|
||||
}
|
||||
}
|
||||
free(list->items);
|
||||
}
|
||||
list->items = NULL;
|
||||
|
||||
@@ -15,7 +15,7 @@ struct path_list
|
||||
void print_path_list(const char *text, const struct path_list *p);
|
||||
|
||||
int path_list_has_path(const struct path_list *list, const char *path);
|
||||
void path_list_clear(struct path_list *list, int free_items);
|
||||
void path_list_clear(struct path_list *list, int free_util);
|
||||
struct path_list_item *path_list_insert(const char *path, struct path_list *list);
|
||||
struct path_list_item *path_list_lookup(const char *path, struct path_list *list);
|
||||
|
||||
|
||||
26
read-cache.c
26
read-cache.c
@@ -7,6 +7,7 @@
|
||||
#include "cache.h"
|
||||
#include "cache-tree.h"
|
||||
#include "refs.h"
|
||||
#include "dir.h"
|
||||
|
||||
/* Index extensions.
|
||||
*
|
||||
@@ -665,7 +666,7 @@ static int check_file_directory_conflict(struct index_state *istate,
|
||||
return retval + has_dir_name(istate, ce, pos, ok_to_replace);
|
||||
}
|
||||
|
||||
int add_index_entry(struct index_state *istate, struct cache_entry *ce, int option)
|
||||
static int add_index_entry_with_check(struct index_state *istate, struct cache_entry *ce, int option)
|
||||
{
|
||||
int pos;
|
||||
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
|
||||
@@ -707,6 +708,22 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
|
||||
pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags));
|
||||
pos = -pos-1;
|
||||
}
|
||||
return pos + 1;
|
||||
}
|
||||
|
||||
int add_index_entry(struct index_state *istate, struct cache_entry *ce, int option)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (option & ADD_CACHE_JUST_APPEND)
|
||||
pos = istate->cache_nr;
|
||||
else {
|
||||
int ret;
|
||||
ret = add_index_entry_with_check(istate, ce, option);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
pos = ret - 1;
|
||||
}
|
||||
|
||||
/* Make sure the array is big enough .. */
|
||||
if (istate->cache_nr == istate->cache_alloc) {
|
||||
@@ -717,7 +734,7 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
|
||||
|
||||
/* Add it in.. */
|
||||
istate->cache_nr++;
|
||||
if (istate->cache_nr > pos)
|
||||
if (istate->cache_nr > pos + 1)
|
||||
memmove(istate->cache + pos + 1,
|
||||
istate->cache + pos,
|
||||
(istate->cache_nr - pos - 1) * sizeof(ce));
|
||||
@@ -782,7 +799,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
|
||||
return updated;
|
||||
}
|
||||
|
||||
int refresh_index(struct index_state *istate, unsigned int flags)
|
||||
int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
|
||||
{
|
||||
int i;
|
||||
int has_errors = 0;
|
||||
@@ -808,6 +825,9 @@ int refresh_index(struct index_state *istate, unsigned int flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
|
||||
continue;
|
||||
|
||||
new = refresh_cache_ent(istate, ce, really, &cache_errno);
|
||||
if (new == ce)
|
||||
continue;
|
||||
|
||||
1
refs.c
1
refs.c
@@ -869,6 +869,7 @@ static int repack_without_ref(const char *refname)
|
||||
die("too long a refname '%s'", list->name);
|
||||
write_or_die(fd, line, len);
|
||||
}
|
||||
close(fd);
|
||||
return commit_lock_file(&packlock);
|
||||
}
|
||||
|
||||
|
||||
@@ -1150,6 +1150,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
die("unknown date format %s", arg);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--log-size")) {
|
||||
revs->show_log_size = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grepping the commit log
|
||||
|
||||
@@ -81,6 +81,7 @@ struct rev_info {
|
||||
const char *log_reencode;
|
||||
const char *subject_prefix;
|
||||
int no_inline;
|
||||
int show_log_size;
|
||||
|
||||
/* Filter by commit log message */
|
||||
struct grep_opt *grep_filter;
|
||||
|
||||
54
setup.c
54
setup.c
@@ -141,7 +141,7 @@ void verify_non_filename(const char *prefix, const char *arg)
|
||||
if (!lstat(name, &st))
|
||||
die("ambiguous argument '%s': both revision and filename\n"
|
||||
"Use '--' to separate filenames from revisions", arg);
|
||||
if (errno != ENOENT)
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
die("'%s': %s", arg, strerror(errno));
|
||||
}
|
||||
|
||||
@@ -223,53 +223,21 @@ int is_inside_work_tree(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* If no worktree was given, and we are outside of a default work tree,
|
||||
* now is the time to set it.
|
||||
*
|
||||
* In other words, if the user calls git with something like
|
||||
*
|
||||
* git --git-dir=/some/where/else/.git bla
|
||||
*
|
||||
* default to /some/where/else as working directory; if the specified
|
||||
* git-dir does not end in "/.git", the cwd is used as working directory.
|
||||
* set_work_tree() is only ever called if you set GIT_DIR explicitely.
|
||||
* The old behaviour (which we retain here) is to set the work tree root
|
||||
* to the cwd, unless overridden by the config, the command line, or
|
||||
* GIT_WORK_TREE.
|
||||
*/
|
||||
const char *set_work_tree(const char *dir)
|
||||
static const char *set_work_tree(const char *dir)
|
||||
{
|
||||
char dir_buffer[PATH_MAX], *rel = NULL;
|
||||
static char buffer[PATH_MAX + 1];
|
||||
int len, suffix_len = strlen(DEFAULT_GIT_DIR_ENVIRONMENT) + 1;
|
||||
char buffer[PATH_MAX + 1];
|
||||
|
||||
/* strip the variable 'dir' of the postfix "/.git" if it has it */
|
||||
len = strlen(dir);
|
||||
if (len > suffix_len &&
|
||||
!strcmp(dir + len - suffix_len, "/" DEFAULT_GIT_DIR_ENVIRONMENT)) {
|
||||
if ((len - suffix_len) >= sizeof(dir_buffer))
|
||||
die("directory name too long");
|
||||
memcpy(dir_buffer, dir, len - suffix_len);
|
||||
dir_buffer[len - suffix_len] = '\0';
|
||||
|
||||
/* are we inside the default work tree? */
|
||||
rel = get_relative_cwd(buffer, sizeof(buffer), dir_buffer);
|
||||
}
|
||||
|
||||
/* if rel is set, the cwd is _not_ the current working tree */
|
||||
if (rel && *rel) {
|
||||
if (!is_absolute_path(dir))
|
||||
set_git_dir(make_absolute_path(dir));
|
||||
dir = dir_buffer;
|
||||
if (chdir(dir))
|
||||
die("cannot chdir to %s: %s", dir, strerror(errno));
|
||||
else
|
||||
strcat(rel, "/");
|
||||
inside_git_dir = 0;
|
||||
} else {
|
||||
rel = NULL;
|
||||
dir = getcwd(buffer, sizeof(buffer));
|
||||
}
|
||||
git_work_tree_cfg = xstrdup(dir);
|
||||
if (!getcwd(buffer, sizeof(buffer)))
|
||||
die ("Could not get the current working directory");
|
||||
git_work_tree_cfg = xstrdup(buffer);
|
||||
inside_work_tree = 1;
|
||||
|
||||
return rel;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -505,7 +505,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
|
||||
*/
|
||||
if (idx_size != 4*256 + nr * 24 + 20 + 20) {
|
||||
munmap(idx_map, idx_size);
|
||||
return error("wrong index file size in %s", path);
|
||||
return error("wrong index v1 file size in %s", path);
|
||||
}
|
||||
} else if (version == 2) {
|
||||
/*
|
||||
@@ -527,7 +527,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p)
|
||||
max_size += (nr - 1)*8;
|
||||
if (idx_size < min_size || idx_size > max_size) {
|
||||
munmap(idx_map, idx_size);
|
||||
return error("wrong index file size in %s", path);
|
||||
return error("wrong index v2 file size in %s", path);
|
||||
}
|
||||
if (idx_size != min_size) {
|
||||
/* make sure we can deal with large pack offsets */
|
||||
|
||||
@@ -290,4 +290,85 @@ test_expect_success '.gitattributes says two and three are text' '
|
||||
fi
|
||||
'
|
||||
|
||||
test_expect_success 'in-tree .gitattributes (1)' '
|
||||
|
||||
echo "one -crlf" >>.gitattributes &&
|
||||
git add .gitattributes &&
|
||||
git commit -m "Add .gitattributes" &&
|
||||
|
||||
rm -rf tmp one dir .gitattributes patch.file three &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
if remove_cr one >/dev/null
|
||||
then
|
||||
echo "Eh? one should not have CRLF"
|
||||
false
|
||||
else
|
||||
: happy
|
||||
fi &&
|
||||
remove_cr three >/dev/null || {
|
||||
echo "Eh? three should still have CRLF"
|
||||
false
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'in-tree .gitattributes (2)' '
|
||||
|
||||
rm -rf tmp one dir .gitattributes patch.file three &&
|
||||
git read-tree --reset HEAD &&
|
||||
git checkout-index -f -q -u -a &&
|
||||
|
||||
if remove_cr one >/dev/null
|
||||
then
|
||||
echo "Eh? one should not have CRLF"
|
||||
false
|
||||
else
|
||||
: happy
|
||||
fi &&
|
||||
remove_cr three >/dev/null || {
|
||||
echo "Eh? three should still have CRLF"
|
||||
false
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'in-tree .gitattributes (3)' '
|
||||
|
||||
rm -rf tmp one dir .gitattributes patch.file three &&
|
||||
git read-tree --reset HEAD &&
|
||||
git checkout-index -u .gitattributes &&
|
||||
git checkout-index -u one dir/two three &&
|
||||
|
||||
if remove_cr one >/dev/null
|
||||
then
|
||||
echo "Eh? one should not have CRLF"
|
||||
false
|
||||
else
|
||||
: happy
|
||||
fi &&
|
||||
remove_cr three >/dev/null || {
|
||||
echo "Eh? three should still have CRLF"
|
||||
false
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'in-tree .gitattributes (4)' '
|
||||
|
||||
rm -rf tmp one dir .gitattributes patch.file three &&
|
||||
git read-tree --reset HEAD &&
|
||||
git checkout-index -u one dir/two three &&
|
||||
git checkout-index -u .gitattributes &&
|
||||
|
||||
if remove_cr one >/dev/null
|
||||
then
|
||||
echo "Eh? one should not have CRLF"
|
||||
false
|
||||
else
|
||||
: happy
|
||||
fi &&
|
||||
remove_cr three >/dev/null || {
|
||||
echo "Eh? three should still have CRLF"
|
||||
false
|
||||
}
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -392,4 +392,9 @@ test_expect_success \
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'strip comments, too' '
|
||||
test ! -z "$(echo "# comment" | git stripspace)" &&
|
||||
test -z "$(echo "# comment" | git stripspace -s)"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -21,7 +21,16 @@ test_expect_success 'update-server-info honors core.sharedRepository' '
|
||||
git commit -m a1 &&
|
||||
umask 0277 &&
|
||||
git update-server-info &&
|
||||
test 444 = $(stat -c %a .git/info/refs)
|
||||
actual="$(ls -l .git/info/refs)" &&
|
||||
case "$actual" in
|
||||
-r--r--r--*)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo Oops, .git/info/refs is not 0444
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -28,6 +28,8 @@ test_rev_parse() {
|
||||
[ $# -eq 0 ] && return
|
||||
}
|
||||
|
||||
# label is-bare is-inside-git is-inside-work prefix
|
||||
|
||||
test_rev_parse toplevel false false true ''
|
||||
|
||||
cd .git || exit 1
|
||||
@@ -53,13 +55,13 @@ export GIT_DIR=../.git
|
||||
export GIT_CONFIG="$(pwd)"/../.git/config
|
||||
|
||||
git config core.bare false
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true work/
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''
|
||||
|
||||
git config core.bare true
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false false ''
|
||||
|
||||
git config --unset core.bare
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true work/
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
|
||||
|
||||
mv ../.git ../repo.git || exit 1
|
||||
export GIT_DIR=../repo.git
|
||||
|
||||
55
t/t2050-git-dir-relative.sh
Executable file
55
t/t2050-git-dir-relative.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='check problems with relative GIT_DIR
|
||||
|
||||
This test creates a working tree state with a file and subdir:
|
||||
|
||||
top (committed several times)
|
||||
subdir (a subdirectory)
|
||||
|
||||
It creates a commit-hook and tests it, then moves .git
|
||||
into the subdir while keeping the worktree location,
|
||||
and tries commits from the top and the subdir, checking
|
||||
that the commit-hook still gets called.'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
COMMIT_FILE="$(pwd)/output"
|
||||
export COMMIT_FILE
|
||||
|
||||
test_expect_success 'Setting up post-commit hook' '
|
||||
mkdir -p .git/hooks &&
|
||||
echo >.git/hooks/post-commit "#!/bin/sh
|
||||
touch \"\${COMMIT_FILE}\"
|
||||
echo Post commit hook was called." &&
|
||||
chmod +x .git/hooks/post-commit'
|
||||
|
||||
test_expect_success 'post-commit hook used ordinarily' '
|
||||
echo initial >top &&
|
||||
git-add top
|
||||
git-commit -m initial &&
|
||||
test -r "${COMMIT_FILE}"
|
||||
'
|
||||
|
||||
rm -rf "${COMMIT_FILE}"
|
||||
mkdir subdir
|
||||
mv .git subdir
|
||||
|
||||
test_expect_success 'post-commit-hook created and used from top dir' '
|
||||
echo changed >top &&
|
||||
git --git-dir subdir/.git add top &&
|
||||
git --git-dir subdir/.git commit -m topcommit &&
|
||||
test -r "${COMMIT_FILE}"
|
||||
'
|
||||
|
||||
rm -rf "${COMMIT_FILE}"
|
||||
|
||||
test_expect_success 'post-commit-hook from sub dir' '
|
||||
echo changed again >top
|
||||
cd subdir &&
|
||||
git --git-dir .git --work-tree .. add ../top &&
|
||||
git --git-dir .git --work-tree .. commit -m subcommit &&
|
||||
test -r "${COMMIT_FILE}"
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -13,26 +13,67 @@ only the updates to dir/sub.'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo initial >top &&
|
||||
mkdir dir &&
|
||||
echo initial >dir/sub &&
|
||||
git add dir/sub top &&
|
||||
git-commit -m initial &&
|
||||
echo changed >top &&
|
||||
echo changed >dir/sub &&
|
||||
echo other >dir/other
|
||||
test_expect_success setup '
|
||||
echo initial >check &&
|
||||
echo initial >top &&
|
||||
mkdir dir1 dir2 &&
|
||||
echo initial >dir1/sub1 &&
|
||||
echo initial >dir1/sub2 &&
|
||||
echo initial >dir2/sub3 &&
|
||||
git add check dir1 dir2 top &&
|
||||
test_tick
|
||||
git-commit -m initial &&
|
||||
|
||||
echo changed >check &&
|
||||
echo changed >top &&
|
||||
echo changed >dir2/sub3 &&
|
||||
rm -f dir1/sub1 &&
|
||||
echo other >dir2/other
|
||||
'
|
||||
|
||||
test_expect_success 'update' 'git add -u dir'
|
||||
test_expect_success update '
|
||||
git add -u dir1 dir2
|
||||
'
|
||||
|
||||
test_expect_success 'update touched correct path' \
|
||||
'test "`git diff-files --name-status dir/sub`" = ""'
|
||||
test_expect_success 'update noticed a removal' '
|
||||
test "$(git-ls-files dir1/sub1)" = ""
|
||||
'
|
||||
|
||||
test_expect_success 'update did not touch other tracked files' \
|
||||
'test "`git diff-files --name-status top`" = "M top"'
|
||||
test_expect_success 'update touched correct path' '
|
||||
test "$(git-diff-files --name-status dir2/sub3)" = ""
|
||||
'
|
||||
|
||||
test_expect_success 'update did not touch untracked files' \
|
||||
'test "`git diff-files --name-status dir/other`" = ""'
|
||||
test_expect_success 'update did not touch other tracked files' '
|
||||
test "$(git-diff-files --name-status check)" = "M check" &&
|
||||
test "$(git-diff-files --name-status top)" = "M top"
|
||||
'
|
||||
|
||||
test_expect_success 'update did not touch untracked files' '
|
||||
test "$(git-ls-files dir2/other)" = ""
|
||||
'
|
||||
|
||||
test_expect_success 'cache tree has not been corrupted' '
|
||||
|
||||
git ls-files -s |
|
||||
sed -e "s/ 0 / /" >expect &&
|
||||
git ls-tree -r $(git write-tree) |
|
||||
sed -e "s/ blob / /" >current &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'update from a subdirectory' '
|
||||
(
|
||||
cd dir1 &&
|
||||
echo more >sub2 &&
|
||||
git add -u sub2
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'change gets noticed' '
|
||||
|
||||
test "$(git diff-files --name-status dir1)" = ""
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -61,29 +61,31 @@ test_expect_success 'setup' '
|
||||
git tag I
|
||||
'
|
||||
|
||||
cat > fake-editor.sh << EOF
|
||||
cat > fake-editor.sh <<\EOF
|
||||
#!/bin/sh
|
||||
test "\$1" = .git/COMMIT_EDITMSG && {
|
||||
test -z "\$FAKE_COMMIT_MESSAGE" || echo "\$FAKE_COMMIT_MESSAGE" > "\$1"
|
||||
test -z "\$FAKE_COMMIT_AMEND" || echo "\$FAKE_COMMIT_AMEND" >> "\$1"
|
||||
case "$1" in
|
||||
*/COMMIT_EDITMSG)
|
||||
test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
|
||||
test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1"
|
||||
exit
|
||||
}
|
||||
test -z "\$EXPECT_COUNT" ||
|
||||
test "\$EXPECT_COUNT" = \$(grep -ve "^#" -e "^$" < "\$1" | wc -l) ||
|
||||
;;
|
||||
esac
|
||||
test -z "$EXPECT_COUNT" ||
|
||||
test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) ||
|
||||
exit
|
||||
test -z "\$FAKE_LINES" && exit
|
||||
grep -v "^#" < "\$1" > "\$1".tmp
|
||||
rm "\$1"
|
||||
cat "\$1".tmp
|
||||
test -z "$FAKE_LINES" && exit
|
||||
grep -v '^#' < "$1" > "$1".tmp
|
||||
rm -f "$1"
|
||||
cat "$1".tmp
|
||||
action=pick
|
||||
for line in \$FAKE_LINES; do
|
||||
case \$line in
|
||||
for line in $FAKE_LINES; do
|
||||
case $line in
|
||||
squash)
|
||||
action="\$line";;
|
||||
action="$line";;
|
||||
*)
|
||||
echo sed -n "\${line}s/^pick/\$action/p"
|
||||
sed -n "\${line}p" < "\$1".tmp
|
||||
sed -n "\${line}s/^pick/\$action/p" < "\$1".tmp >> "\$1"
|
||||
echo sed -n "${line}s/^pick/$action/p"
|
||||
sed -n "${line}p" < "$1".tmp
|
||||
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
|
||||
action=pick;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -147,4 +147,16 @@ test_expect_success 'git add with filemode=0, symlinks=0 prefers stage 2 over st
|
||||
git ls-files --stage | grep "^120000 .* 0 symlink$"
|
||||
'
|
||||
|
||||
test_expect_success 'git add --refresh' '
|
||||
>foo && git add foo && git commit -a -m "commit all" &&
|
||||
test -z "`git diff-index HEAD -- foo`" &&
|
||||
git read-tree HEAD &&
|
||||
case "`git diff-index HEAD -- foo`" in
|
||||
:100644" "*"M foo") echo ok;;
|
||||
*) echo fail; (exit 1);;
|
||||
esac &&
|
||||
git add --refresh -- foo &&
|
||||
test -z "`git diff-index HEAD -- foo`"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -7,6 +7,12 @@ test_description='quoted output'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
P1='pathname with HT'
|
||||
: >"$P1" 2>&1 && test -f "$P1" && rm -f "$P1" || {
|
||||
echo >&2 'Filesystem does not support HT in names'
|
||||
test_done
|
||||
}
|
||||
|
||||
FN='濱野'
|
||||
GN='純'
|
||||
HT=' '
|
||||
|
||||
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
|
||||
|
||||
pull_to_client 3rd "A" $((1*3)) # old fails
|
||||
|
||||
test_expect_success "clone shallow" "git-clone --depth 2 . shallow"
|
||||
test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
|
||||
|
||||
(cd shallow; git count-objects -v) > count.shallow
|
||||
|
||||
|
||||
@@ -145,4 +145,12 @@ test_expect_success 'bundle does not prerequisite objects' '
|
||||
test 4 = $(git verify-pack -v bundle.pack | wc -l)
|
||||
'
|
||||
|
||||
test_expect_success 'bundle should be able to create a full history' '
|
||||
|
||||
cd "$D" &&
|
||||
git tag -a -m '1.0' v1.0 master &&
|
||||
git bundle create bundle4 v1.0
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -51,7 +51,7 @@ diff expected current'
|
||||
cd "$base_dir"
|
||||
|
||||
test_expect_success 'cloning with reference (no -l -s)' \
|
||||
'git clone --reference B A D'
|
||||
'git clone --reference B file://`pwd`/A D'
|
||||
|
||||
cd "$base_dir"
|
||||
|
||||
|
||||
@@ -8,13 +8,16 @@ D=`pwd`
|
||||
test_expect_success 'preparing origin repository' '
|
||||
: >file && git add . && git commit -m1 &&
|
||||
git clone --bare . a.git &&
|
||||
git clone --bare . x
|
||||
git clone --bare . x &&
|
||||
test "$(GIT_CONFIG=a.git/config git config --bool core.bare)" = true &&
|
||||
test "$(GIT_CONFIG=x/config git config --bool core.bare)" = true
|
||||
'
|
||||
|
||||
test_expect_success 'local clone without .git suffix' '
|
||||
cd "$D" &&
|
||||
git clone -l -s a b &&
|
||||
cd b &&
|
||||
test "$(GIT_CONFIG=.git/config git config --bool core.bare)" = false &&
|
||||
git fetch
|
||||
'
|
||||
|
||||
@@ -43,4 +46,21 @@ test_expect_success 'local clone from x.git that does not exist' '
|
||||
fi
|
||||
'
|
||||
|
||||
test_expect_success 'With -no-hardlinks, local will make a copy' '
|
||||
cd "$D" &&
|
||||
git clone --bare --no-hardlinks x w &&
|
||||
cd w &&
|
||||
linked=$(find objects -type f ! -links 1 | wc -l) &&
|
||||
test 0 = $linked
|
||||
'
|
||||
|
||||
test_expect_success 'Even without -l, local will make a hardlink' '
|
||||
cd "$D" &&
|
||||
rm -fr w &&
|
||||
git clone -l --bare x w &&
|
||||
cd w &&
|
||||
copied=$(find objects -type f -links 1 | wc -l) &&
|
||||
test 0 = $copied
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
67
t/t6027-merge-binary.sh
Executable file
67
t/t6027-merge-binary.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='ask merge-recursive to merge binary files'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
cat ../test4012.png >m &&
|
||||
git add m &&
|
||||
git ls-files -s | sed -e "s/ 0 / 1 /" >E1 &&
|
||||
test_tick &&
|
||||
git commit -m "initial" &&
|
||||
|
||||
git branch side &&
|
||||
echo frotz >a &&
|
||||
git add a &&
|
||||
echo nitfol >>m &&
|
||||
git add a m &&
|
||||
git ls-files -s a >E0 &&
|
||||
git ls-files -s m | sed -e "s/ 0 / 3 /" >E3 &&
|
||||
test_tick &&
|
||||
git commit -m "master adds some" &&
|
||||
|
||||
git checkout side &&
|
||||
echo rezrov >>m &&
|
||||
git add m &&
|
||||
git ls-files -s m | sed -e "s/ 0 / 2 /" >E2 &&
|
||||
test_tick &&
|
||||
git commit -m "side modifies" &&
|
||||
|
||||
git tag anchor &&
|
||||
|
||||
cat E0 E1 E2 E3 >expect
|
||||
'
|
||||
|
||||
test_expect_success resolve '
|
||||
|
||||
rm -f a* m* &&
|
||||
git reset --hard anchor &&
|
||||
|
||||
if git merge -s resolve master
|
||||
then
|
||||
echo Oops, should not have succeeded
|
||||
false
|
||||
else
|
||||
git ls-files -s >current
|
||||
diff -u current expect
|
||||
fi
|
||||
'
|
||||
|
||||
test_expect_success recursive '
|
||||
|
||||
rm -f a* m* &&
|
||||
git reset --hard anchor &&
|
||||
|
||||
if git merge -s recursive master
|
||||
then
|
||||
echo Oops, should not have succeeded
|
||||
false
|
||||
else
|
||||
git ls-files -s >current
|
||||
diff -u current expect
|
||||
fi
|
||||
'
|
||||
|
||||
test_done
|
||||
123
t/t7004-tag.sh
123
t/t7004-tag.sh
@@ -5,7 +5,7 @@
|
||||
|
||||
test_description='git-tag
|
||||
|
||||
Basic tests for operations with tags.'
|
||||
Tests for operations with tags.'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
@@ -16,11 +16,15 @@ tag_exists () {
|
||||
}
|
||||
|
||||
# todo: git tag -l now returns always zero, when fixed, change this test
|
||||
test_expect_success 'listing all tags in an empty tree should succeed' \
|
||||
'git tag -l'
|
||||
test_expect_success 'listing all tags in an empty tree should succeed' '
|
||||
git tag -l &&
|
||||
git tag
|
||||
'
|
||||
|
||||
test_expect_success 'listing all tags in an empty tree should output nothing' \
|
||||
'test `git-tag -l | wc -l` -eq 0'
|
||||
test_expect_success 'listing all tags in an empty tree should output nothing' '
|
||||
test `git-tag -l | wc -l` -eq 0 &&
|
||||
test `git-tag | wc -l` -eq 0
|
||||
'
|
||||
|
||||
test_expect_failure 'looking for a tag in an empty tree should fail' \
|
||||
'tag_exists mytag'
|
||||
@@ -49,11 +53,15 @@ test_expect_success 'creating a tag using default HEAD should succeed' '
|
||||
git tag mytag
|
||||
'
|
||||
|
||||
test_expect_success 'listing all tags if one exists should succeed' \
|
||||
'git-tag -l'
|
||||
test_expect_success 'listing all tags if one exists should succeed' '
|
||||
git-tag -l &&
|
||||
git-tag
|
||||
'
|
||||
|
||||
test_expect_success 'listing all tags if one exists should output that tag' \
|
||||
'test `git-tag -l` = mytag'
|
||||
test_expect_success 'listing all tags if one exists should output that tag' '
|
||||
test `git-tag -l` = mytag &&
|
||||
test `git-tag` = mytag
|
||||
'
|
||||
|
||||
# pattern matching:
|
||||
|
||||
@@ -165,6 +173,8 @@ test_expect_success 'listing all tags should print them ordered' '
|
||||
git tag v1.0 &&
|
||||
git tag t210 &&
|
||||
git tag -l > actual &&
|
||||
git diff expect actual &&
|
||||
git tag > actual &&
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
@@ -264,6 +274,10 @@ test_expect_failure \
|
||||
'trying to verify a non-annotated and non-signed tag should fail' \
|
||||
'git-tag -v non-annotated-tag'
|
||||
|
||||
test_expect_failure \
|
||||
'trying to verify many non-annotated or unknown tags, should fail' \
|
||||
'git-tag -v unknown-tag1 non-annotated-tag unknown-tag2'
|
||||
|
||||
# creating annotated tags:
|
||||
|
||||
get_tag_msg () {
|
||||
@@ -306,6 +320,45 @@ test_expect_success \
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
cat >inputmsg <<EOF
|
||||
A message from the
|
||||
standard input
|
||||
EOF
|
||||
get_tag_header stdin-annotated-tag $commit commit $time >expect
|
||||
cat inputmsg >>expect
|
||||
test_expect_success 'creating an annotated tag with -F - should succeed' '
|
||||
git-tag -F - stdin-annotated-tag <inputmsg &&
|
||||
get_tag_msg stdin-annotated-tag >actual &&
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
test_expect_success \
|
||||
'trying to create a tag with a non-existing -F file should fail' '
|
||||
! test -f nonexistingfile &&
|
||||
! tag_exists notag &&
|
||||
! git-tag -F nonexistingfile notag &&
|
||||
! tag_exists notag
|
||||
'
|
||||
|
||||
test_expect_success \
|
||||
'trying to create tags giving many -m or -F options should fail' '
|
||||
echo "message file 1" >msgfile1 &&
|
||||
echo "message file 2" >msgfile2 &&
|
||||
! tag_exists msgtag &&
|
||||
! git-tag -m "message 1" -m "message 2" msgtag &&
|
||||
! tag_exists msgtag &&
|
||||
! git-tag -F msgfile1 -F msgfile2 msgtag &&
|
||||
! tag_exists msgtag &&
|
||||
! git-tag -m "message 1" -F msgfile1 msgtag &&
|
||||
! tag_exists msgtag &&
|
||||
! git-tag -F msgfile1 -m "message 1" msgtag &&
|
||||
! tag_exists msgtag &&
|
||||
! git-tag -F msgfile1 -m "message 1" -F msgfile2 msgtag &&
|
||||
! tag_exists msgtag &&
|
||||
! git-tag -m "message 1" -F msgfile1 -m "message 2" msgtag &&
|
||||
! tag_exists msgtag
|
||||
'
|
||||
|
||||
# blank and empty messages:
|
||||
|
||||
get_tag_header empty-annotated-tag $commit commit $time >expect
|
||||
@@ -551,6 +604,12 @@ test_expect_success \
|
||||
! git-tag -v file-annotated-tag
|
||||
'
|
||||
|
||||
test_expect_success \
|
||||
'trying to verify two annotated non-signed tags should fail' '
|
||||
tag_exists annotated-tag file-annotated-tag &&
|
||||
! git-tag -v annotated-tag file-annotated-tag
|
||||
'
|
||||
|
||||
# creating and verifying signed tags:
|
||||
|
||||
gpg --version >/dev/null
|
||||
@@ -589,9 +648,55 @@ test_expect_success 'creating a signed tag with -m message should succeed' '
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
cat >sigmsgfile <<EOF
|
||||
Another signed tag
|
||||
message in a file.
|
||||
EOF
|
||||
get_tag_header file-signed-tag $commit commit $time >expect
|
||||
cat sigmsgfile >>expect
|
||||
echo '-----BEGIN PGP SIGNATURE-----' >>expect
|
||||
test_expect_success \
|
||||
'creating a signed tag with -F messagefile should succeed' '
|
||||
git-tag -s -F sigmsgfile file-signed-tag &&
|
||||
get_tag_msg file-signed-tag >actual &&
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
cat >siginputmsg <<EOF
|
||||
A signed tag message from
|
||||
the standard input
|
||||
EOF
|
||||
get_tag_header stdin-signed-tag $commit commit $time >expect
|
||||
cat siginputmsg >>expect
|
||||
echo '-----BEGIN PGP SIGNATURE-----' >>expect
|
||||
test_expect_success 'creating a signed tag with -F - should succeed' '
|
||||
git-tag -s -F - stdin-signed-tag <siginputmsg &&
|
||||
get_tag_msg stdin-signed-tag >actual &&
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
test_expect_success \
|
||||
'trying to create a signed tag with non-existing -F file should fail' '
|
||||
! test -f nonexistingfile &&
|
||||
! tag_exists nosigtag &&
|
||||
! git-tag -s -F nonexistingfile nosigtag &&
|
||||
! tag_exists nosigtag
|
||||
'
|
||||
|
||||
test_expect_success 'verifying a signed tag should succeed' \
|
||||
'git-tag -v signed-tag'
|
||||
|
||||
test_expect_success 'verifying two signed tags in one command should succeed' \
|
||||
'git-tag -v signed-tag file-signed-tag'
|
||||
|
||||
test_expect_success \
|
||||
'verifying many signed and non-signed tags should fail' '
|
||||
! git-tag -v signed-tag annotated-tag &&
|
||||
! git-tag -v file-annotated-tag file-signed-tag &&
|
||||
! git-tag -v annotated-tag file-signed-tag file-annotated-tag &&
|
||||
! git-tag -v signed-tag annotated-tag file-signed-tag
|
||||
'
|
||||
|
||||
test_expect_success 'verifying a forged tag should fail' '
|
||||
forged=$(git cat-file tag signed-tag |
|
||||
sed -e "s/signed-tag/forged-tag/" |
|
||||
|
||||
@@ -175,4 +175,21 @@ test_expect_success 'checkout superproject with subproject already present' '
|
||||
git-checkout master
|
||||
'
|
||||
|
||||
test_expect_success 'apply submodule diff' '
|
||||
git branch second &&
|
||||
(
|
||||
cd lib &&
|
||||
echo s >s &&
|
||||
git add s &&
|
||||
git commit -m "change subproject"
|
||||
) &&
|
||||
git update-index --add lib &&
|
||||
git-commit -m "change lib" &&
|
||||
git-format-patch -1 --stdout >P.diff &&
|
||||
git checkout second &&
|
||||
git apply --index P.diff &&
|
||||
D=$(git diff --cached master) &&
|
||||
test -z "$D"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
48
t/t9116-git-svn-log.sh
Executable file
48
t/t9116-git-svn-log.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2007 Eric Wong
|
||||
#
|
||||
|
||||
test_description='git-svn log tests'
|
||||
. ./lib-git-svn.sh
|
||||
|
||||
test_expect_success 'setup repository and import' "
|
||||
mkdir import &&
|
||||
cd import &&
|
||||
for i in trunk branches/a branches/b \
|
||||
tags/0.1 tags/0.2 tags/0.3; do
|
||||
mkdir -p \$i && \
|
||||
echo hello >> \$i/README || exit 1
|
||||
done && \
|
||||
svn import -m test . $svnrepo
|
||||
cd .. &&
|
||||
git-svn init $svnrepo -T trunk -b branches -t tags &&
|
||||
git-svn fetch &&
|
||||
git reset --hard trunk &&
|
||||
echo bye >> README &&
|
||||
git commit -a -m bye &&
|
||||
git svn dcommit &&
|
||||
git reset --hard a &&
|
||||
echo why >> FEEDME &&
|
||||
git update-index --add FEEDME &&
|
||||
git commit -m feedme &&
|
||||
git svn dcommit &&
|
||||
git reset --hard trunk &&
|
||||
echo aye >> README &&
|
||||
git commit -a -m aye &&
|
||||
git svn dcommit
|
||||
"
|
||||
|
||||
test_expect_success 'run log' "
|
||||
git reset --hard a &&
|
||||
git svn log -r2 trunk | grep ^r2 &&
|
||||
git svn log -r4 trunk | grep ^r4 &&
|
||||
git svn log -r3 | grep ^r3
|
||||
"
|
||||
|
||||
test_expect_success 'run log against a from trunk' "
|
||||
git reset --hard trunk &&
|
||||
git svn log -r3 a | grep ^r3
|
||||
"
|
||||
|
||||
test_done
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user