Merge commit '96c48153c9a2905fb2f1d588c11e36272635cb79'

This commit is contained in:
Johannes Sixt
2007-07-21 23:15:20 +02:00
33 changed files with 1868 additions and 199 deletions

View File

@@ -1,4 +1,4 @@
GIT v1.5.3 Release Notes (draft)
GIT v1.5.3 Release Notes
========================
Updates since v1.5.2
@@ -10,8 +10,23 @@ Updates since v1.5.2
* Thee are a handful pack-objects changes to help you cope better with
repositories with pathologically large blobs in them.
* For people who need to import from Perforce, a front-end for
fast-import is in contrib/fast-import/ now.
* Comes with git-gui 0.8.0.
* Comes with updated gitk.
* New commands and options.
- "git log" learned a new option '--follow', to follow
renaming history of a single file.
- "git-filter-branch" is a reborn cg-admin-rewritehist.
- "git-cvsserver" learned new options (--base-path, --export-all,
--strict-paths) inspired by git-daemon.
- "git-submodule" command helps you manage the projects from
the superproject that contain them.
@@ -36,9 +51,45 @@ Updates since v1.5.2
- "git repack" can be told to split resulting packs to avoid
exceeding limit specified with "--max-pack-size".
- "git fsck" gained --verbose option. This is really really
verbose but it might help you identify exact commit that is
corrupt in your repository.
- "git format-patch" learned --numbered-files option. This
may be useful for MH users.
- "git tag -n -l" shows tag annotations while listing tags.
- "git cvsimport" can optionally use the separate-remote layout.
- "git blame" can be told to see through commits that changes
whitespaces and indentation levels with "-w" option.
- "git send-email" can be told not to thread the messages when
sending out more than one patches.
- "git config" learned NUL terminated output format via -z to
help scripts.
* Updated behavior of existing commands.
- "git push" pretends that you immediately fetched back from
- "git mergetool" chooses its backend more wisely, taking
notice of its environment such as use of X, Gnome/KDE, etc.
- "gitweb" shows merge commits a lot nicer than before. The
default view uses more compact --cc format, while the UI
allows to choose normal diff with any parent.
- snapshot files "gitweb" creates from a repository at
$path/$project/.git are more useful. We use $project part
in the filename, which we used to discard.
- "git cvsimort" creates lightweight tag; there is not any
interesting information we can record in an annotated tag,
and the handcrafted ones the old code created was not
properly formed anyway.
- "git-push" pretends that you immediately fetched back from
the remote by updating corresponding remote tracking
branches if you have any.
@@ -48,17 +99,25 @@ Updates since v1.5.2
- "git-apply --whitespace=strip" removes blank lines added at
the end of the file.
- fetch over git native protocols with -v shows connection
- "git-fetch" over git native protocols with -v shows connection
status, and the IP address of the other end, to help
diagnosing problems.
- core.legacyheaders is no more, although we still can read
objects created in a new loose object format.
- We used to have core.legacyheaders configuration, when
set to false, allowed git to write loose objects in a format
that mimicks the format used by objects stored in packs. It
turns out that this was not so useful. Although we will
continue to read objects written in that format, we do not
honor that configuration anymore and create loose objects in
the legacy/traditional format.
- "--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
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
@@ -68,10 +127,25 @@ Updates since v1.5.2
- new-workdir script (in contrib) can now be used with a bare
repository.
- "git-mergetool" learned to use gvimdiff.
- "gitview" (in contrib) has a better blame interface.
- "git log" and friends did not handle a commit log message
that is larger than 16kB; they do now.
- "--pretty=oneline" output format for "git log" and friends
deals with "malformed" commit log messages that have more
than one lines in the first paragraph better. We used to
show the first line, cutting the title at mid-sentence; we
concatenate them into a single line and treat the result as
"oneline".
* Builds
-
- old-style function definitions (most notably, a function
without parameter defined with "func()", not "func(void)")
have been eradicated.
* Performance Tweaks
@@ -88,6 +162,10 @@ Updates since v1.5.2
the object requested the last time, which exploits the
locality of references.
- verifying pack contents done by "git fsck --full" got boost
by carefully choosing the order to verify objects in them.
Fixes since v1.5.2
------------------
@@ -96,14 +174,11 @@ this release, unless otherwise noted.
* Bugfixes
- .... This has not
been backported to 1.5.2.x series, as it is rather an
intrusive change.
- "gitweb" had trouble handling non UTF-8 text with older
Encode.pm Perl module.
--
exec >/var/tmp/1
O=v1.5.2-45-ged82edc
O=v1.5.2-172-g1a8b769
O=v1.5.2.2-603-g7c85173
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint

View File

@@ -172,6 +172,13 @@ repository that ends in "/.git" is assumed to be not bare (bare =
false), while all other repositories are assumed to be bare (bare
= true).
core.worktree::
Set the path to the working tree. The value will not be
used in combination with repositories found automatically in
a .git directory (i.e. $GIT_DIR is not set).
This can be overriden by the GIT_WORK_TREE environment
variable and the '--work-tree' command line option.
core.logAllRefUpdates::
Updates to a ref <ref> is logged to the file
"$GIT_DIR/logs/<ref>", by appending the new and old

View File

@@ -9,9 +9,9 @@ git-config - Get and set repository or global options
SYNOPSIS
--------
[verse]
'git-config' [--system | --global] [-z|--null] name [value [value_regex]]
'git-config' [--system | --global] --add name value
'git-config' [--system | --global] --replace-all name [value [value_regex]]
'git-config' [--system | --global] [type] [-z|--null] name [value [value_regex]]
'git-config' [--system | --global] [type] --add name value
'git-config' [--system | --global] [type] --replace-all name [value [value_regex]]
'git-config' [--system | --global] [type] [-z|--null] --get name [value_regex]
'git-config' [--system | --global] [type] [-z|--null] --get-all name [value_regex]
'git-config' [--system | --global] [type] [-z|--null] --get-regexp name_regex [value_regex]
@@ -37,8 +37,7 @@ prepend a single exclamation mark in front (see also <<EXAMPLES>>).
The type specifier can be either '--int' or '--bool', which will make
'git-config' ensure that the variable(s) are of the given type and
convert the value to the canonical form (simple decimal number for int,
a "true" or "false" string for bool). Type specifiers currently only
take effect for reading operations. If no type specifier is passed,
a "true" or "false" string for bool). If no type specifier is passed,
no checks or transformations are performed on the value.
This command will fail if:

View File

@@ -90,8 +90,15 @@ OPTIONS
Show `$GIT_DIR` if defined else show the path to the .git directory.
--is-inside-git-dir::
Return "true" if we are in the git directory, otherwise "false".
Some commands require to be run in a working directory.
When the current working directory is below the repository
directory print "true", otherwise "false".
--is-inside-work-tree::
When the current working directory is inside the work tree of the
repository print "true", otherwise "false".
--is-bare-repository::
When the repository is bare print "true", otherwise "false".
--short, --short=number::
Instead of outputting the full SHA1 values of object names try to

View File

@@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
[--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
[--help] COMMAND [ARGS]
DESCRIPTION
-----------
@@ -103,6 +104,14 @@ OPTIONS
Set the path to the repository. This can also be controlled by
setting the GIT_DIR environment variable.
--work-tree=<path>::
Set the path to the working tree. The value will not be
used in combination with repositories found automatically in
a .git directory (i.e. $GIT_DIR is not set).
This can also be controlled by setting the GIT_WORK_TREE
environment variable and the core.worktree configuration
variable.
--bare::
Same as --git-dir=`pwd`.
@@ -347,6 +356,13 @@ git so take care if using Cogito etc.
specifies a path to use instead of the default `.git`
for the base of the repository.
'GIT_WORK_TREE'::
Set the path to the working tree. The value will not be
used in combination with repositories found automatically in
a .git directory (i.e. $GIT_DIR is not set).
This can also be controlled by the '--work-tree' command line
option and the core.worktree configuration variable.
git Commits
~~~~~~~~~~~
'GIT_AUTHOR_NAME'::
@@ -396,6 +412,16 @@ other
'GIT_PAGER'::
This environment variable overrides `$PAGER`.
'GIT_FLUSH'::
If this environment variable is set to "1", then commands such
as git-blame (in incremental mode), git-rev-list, git-log,
git-whatchanged, etc., will force a flush of the output stream
after each commit-oriented record have been flushed. If this
variable is set to "0", the output of these commands will be done
using completely buffered I/O. If this environment variable is
not set, git will choose buffered or record-oriented flushing
based on whether stdout appears to be redirected to a file or not.
'GIT_TRACE'::
If this variable is set to "1", "2" or "true" (comparison
is case insensitive), git will print `trace:` messages on

View File

@@ -1459,6 +1459,7 @@ static void found_guilty_entry(struct blame_entry *ent)
printf("boundary\n");
}
write_filename_info(suspect->path);
maybe_flush_or_die(stdout, "stdout");
}
}

View File

@@ -138,9 +138,33 @@ free_strings:
return ret;
}
char *normalize_value(const char *key, const char *value)
{
char *normalized;
if (!value)
return NULL;
if (type == T_RAW)
normalized = xstrdup(value);
else {
normalized = xmalloc(64);
if (type == T_INT) {
int v = git_config_int(key, value);
sprintf(normalized, "%d", v);
}
else if (type == T_BOOL)
sprintf(normalized, "%s",
git_config_bool(key, value) ? "true" : "false");
}
return normalized;
}
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = 0;
char* value;
setup_git_directory_gently(&nongit);
while (1 < argc) {
@@ -217,9 +241,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
use_key_regexp = 1;
do_all = 1;
return get_value(argv[2], NULL);
} else
return git_config_set(argv[1], argv[2]);
} else {
value = normalize_value(argv[1], argv[2]);
return git_config_set(argv[1], value);
}
case 4:
if (!strcmp(argv[1], "--unset"))
return git_config_set_multivar(argv[2], NULL, argv[3], 0);
@@ -235,17 +260,21 @@ int cmd_config(int argc, const char **argv, const char *prefix)
use_key_regexp = 1;
do_all = 1;
return get_value(argv[2], argv[3]);
} else if (!strcmp(argv[1], "--add"))
return git_config_set_multivar(argv[2], argv[3], "^$", 0);
else if (!strcmp(argv[1], "--replace-all"))
return git_config_set_multivar(argv[2], argv[3], NULL, 1);
else
return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
} else if (!strcmp(argv[1], "--add")) {
value = normalize_value(argv[2], argv[3]);
return git_config_set_multivar(argv[2], value, "^$", 0);
} else if (!strcmp(argv[1], "--replace-all")) {
value = normalize_value(argv[2], argv[3]);
return git_config_set_multivar(argv[2], value, NULL, 1);
} else {
value = normalize_value(argv[1], argv[2]);
return git_config_set_multivar(argv[1], value, argv[3], 0);
}
case 5:
if (!strcmp(argv[1], "--replace-all"))
return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
if (!strcmp(argv[1], "--replace-all")) {
value = normalize_value(argv[2], argv[3]);
return git_config_set_multivar(argv[2], value, argv[4], 1);
}
case 1:
default:
usage(git_config_set_usage);

View File

@@ -470,7 +470,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
}
if (require_work_tree &&
(is_bare_repository() || is_inside_git_dir()))
(!is_inside_work_tree() || is_inside_git_dir()))
die("This operation must be run in a work tree");
pathspec = get_pathspec(prefix, argv + i);

View File

@@ -100,7 +100,7 @@ static void show_commit(struct commit *commit)
printf("%s%c", buf, hdr_termination);
free(buf);
}
fflush(stdout);
maybe_flush_or_die(stdout, "stdout");
if (commit->parents) {
free_commit_list(commit->parents);
commit->parents = NULL;

View File

@@ -352,6 +352,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "false");
continue;
}
if (!strcmp(arg, "--is-inside-work-tree")) {
printf("%s\n", is_inside_work_tree() ? "true"
: "false");
continue;
}
if (!strcmp(arg, "--is-bare-repository")) {
printf("%s\n", is_bare_repository() ? "true"
: "false");
continue;
}
if (!prefixcmp(arg, "--since=")) {
show_datestring("--max-age=", arg+8);
continue;

View File

@@ -1,58 +1,79 @@
#include "builtin.h"
#include "cache.h"
/*
* Remove empty lines from the beginning and end.
* Remove trailing spaces from a line.
*
* Turn multiple consecutive empty lines into just one
* empty line. Return true if it is an incomplete line.
* If the line ends with newline, it will be removed too.
* Returns the new length of the string.
*/
static int cleanup(char *line)
static int cleanup(char *line, int len)
{
int len = strlen(line);
if (len) {
if (line[len - 1] == '\n')
len--;
if (len && line[len-1] == '\n') {
if (len == 1)
return 0;
do {
unsigned char c = line[len-2];
while (len) {
unsigned char c = line[len - 1];
if (!isspace(c))
break;
line[len-2] = '\n';
len--;
line[len] = 0;
} while (len > 1);
return 0;
}
line[len] = 0;
}
return 1;
return len;
}
static void stripspace(FILE *in, FILE *out)
/*
* Remove empty lines from the beginning and end
* and also trailing spaces from every line.
*
* Turn multiple consecutive empty lines between paragraphs
* into just one empty line.
*
* If the input has only empty lines and spaces,
* no output will be produced.
*
* Enable skip_comments to skip every line starting with "#".
*/
void stripspace(FILE *in, FILE *out, int skip_comments)
{
int empties = -1;
int incomplete = 0;
char line[1024];
int alloc = 1024;
char *line = xmalloc(alloc);
while (fgets(line, sizeof(line), in)) {
incomplete = cleanup(line);
while (fgets(line, alloc, in)) {
int len = strlen(line);
while (len == alloc - 1 && line[len - 1] != '\n') {
alloc = alloc_nr(alloc);
line = xrealloc(line, alloc);
fgets(line + len, alloc - len, in);
len += strlen(line + len);
}
if (skip_comments && line[0] == '#')
continue;
len = cleanup(line, len);
/* Not just an empty line? */
if (line[0] != '\n') {
if (len) {
if (empties > 0)
fputc('\n', out);
empties = 0;
fputs(line, out);
fputc('\n', out);
continue;
}
if (empties < 0)
continue;
empties++;
}
if (incomplete)
fputc('\n', out);
free(line);
}
int cmd_stripspace(int argc, const char **argv, const char *prefix)
{
stripspace(stdin, stdout);
stripspace(stdin, stdout, 0);
return 0;
}

View File

@@ -7,6 +7,7 @@ extern const char git_version_string[];
extern const char git_usage_string[];
extern void help_unknown_cmd(const char *cmd);
extern void stripspace(FILE *in, FILE *out, int skip_comments);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
extern void prune_packed_objects(int);

View File

@@ -192,6 +192,7 @@ enum object_type {
};
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -207,6 +208,7 @@ enum object_type {
extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
extern int is_inside_git_dir(void);
extern int is_inside_work_tree(void);
extern const char *get_git_dir(void);
extern char *get_object_directory(void);
extern char *get_refs_directory(void);
@@ -534,6 +536,8 @@ extern char git_default_name[MAX_GITNAME];
extern const char *git_commit_encoding;
extern const char *git_log_output_encoding;
/* IO helper functions */
extern void maybe_flush_or_die(FILE *, const char *);
extern int copy_fd(int ifd, int ofd);
extern int read_in_full(int fd, void *buf, size_t count);
extern int write_in_full(int fd, const void *buf, size_t count);

View File

@@ -593,6 +593,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
env_unsetenv(env, ALTERNATE_DB_ENVIRONMENT);
env_unsetenv(env, DB_ENVIRONMENT);
env_unsetenv(env, GIT_DIR_ENVIRONMENT);
env_unsetenv(env, GIT_WORK_TREE_ENVIRONMENT);
env_unsetenv(env, GRAFT_ENVIRONMENT);
env_unsetenv(env, INDEX_ENVIRONMENT);
pid = spawnvpe_pipe("sh", argv, env, pipefd[1], pipefd[0]);

View File

@@ -312,9 +312,10 @@ case "$GIT_DIR" in
/*)
;;
*)
export GIT_DIR="$(pwd)/../../$GIT_DIR"
GIT_DIR="$(pwd)/../../$GIT_DIR"
;;
esac
export GIT_DIR GIT_WORK_TREE=.
export GIT_INDEX_FILE="$(pwd)/../index"
git-read-tree # seed the index file

View File

@@ -29,11 +29,7 @@ set_reflog_action() {
}
is_bare_repository () {
git-config --bool --get core.bare ||
case "$GIT_DIR" in
.git | */.git) echo false ;;
*) echo true ;;
esac
git-rev-parse --is-bare-repository
}
cd_to_toplevel () {
@@ -48,7 +44,7 @@ cd_to_toplevel () {
}
require_work_tree () {
test $(is_bare_repository) = false &&
test $(git-rev-parse --is-inside-work-tree) = true &&
test $(git-rev-parse --is-inside-git-dir) = false ||
die "fatal: $0 cannot be used without a working tree."
}

View File

@@ -596,8 +596,7 @@ sub post_fetch_checkout {
my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
return if -f $index;
chomp(my $bare = `git config --bool --get core.bare`);
return if $bare eq 'true';
return if command_oneline(qw/rev-parse --is-inside-work-tree/) eq 'false';
return if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
print STDERR "Checked out HEAD:\n ",
@@ -787,12 +786,12 @@ sub read_repo_config {
sub extract_metadata {
my $id = shift or return (undef, undef, undef);
my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+)
my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+)
\s([a-f\d\-]+)$/x);
if (!defined $rev || !$uuid || !$url) {
# some of the original repositories I made had
# identifiers like this:
($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
}
return ($url, $rev, $uuid);
}
@@ -804,20 +803,29 @@ sub cmt_metadata {
sub working_head_info {
my ($head, $refs) = @_;
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
while (my $hash = <$fh>) {
chomp($hash);
my ($url, $rev, $uuid) = cmt_metadata($hash);
my ($fh, $ctx) = command_output_pipe('log', $head);
my $hash;
my %max;
while (<$fh>) {
if ( m{^commit ($::sha1)$} ) {
unshift @$refs, $hash if $hash and $refs;
$hash = $1;
next;
}
next unless s{^\s*(git-svn-id:)}{$1};
my ($url, $rev, $uuid) = extract_metadata($_);
if (defined $url && defined $rev) {
next if $max{$url} and $max{$url} < $rev;
if (my $gs = Git::SVN->find_by_url($url)) {
my $c = $gs->rev_db_get($rev);
if ($c && $c eq $hash) {
close $fh; # break the pipe
return ($url, $rev, $uuid, $gs);
} else {
$max{$url} ||= $gs->rev_db_max;
}
}
}
unshift @$refs, $hash if $refs;
}
command_close_pipe($fh, $ctx);
(undef, undef, undef, undef);
@@ -1966,16 +1974,19 @@ sub rebuild {
return;
}
print "Rebuilding $db_path ...\n";
my ($rev_list, $ctx) = command_output_pipe("rev-list", $self->refname);
my ($log, $ctx) = command_output_pipe("log", $self->refname);
my $latest;
my $full_url = $self->full_url;
remove_username($full_url);
my $svn_uuid;
while (<$rev_list>) {
chomp;
my $c = $_;
die "Non-SHA1: $c\n" unless $c =~ /^$::sha1$/o;
my ($url, $rev, $uuid) = ::cmt_metadata($c);
my $c;
while (<$log>) {
if ( m{^commit ($::sha1)$} ) {
$c = $1;
next;
}
next unless s{^\s*(git-svn-id:)}{$1};
my ($url, $rev, $uuid) = ::extract_metadata($_);
remove_username($url);
# ignore merges (from set-tree)
@@ -1993,7 +2004,7 @@ sub rebuild {
$self->rev_db_set($rev, $c);
print "r$rev = $c\n";
}
command_close_pipe($rev_list, $ctx);
command_close_pipe($log, $ctx);
print "Done rebuilding $db_path\n";
}
@@ -2925,6 +2936,7 @@ sub new {
SVN::Client::get_ssl_server_trust_file_provider(),
SVN::Client::get_simple_prompt_provider(
\&Git::SVN::Prompt::simple, 2),
SVN::Client::get_ssl_client_cert_file_provider(),
SVN::Client::get_ssl_client_cert_prompt_provider(
\&Git::SVN::Prompt::ssl_client_cert, 2),
SVN::Client::get_ssl_client_cert_pw_prompt_provider(

45
git-tag.sh Normal file → Executable file
View File

@@ -19,28 +19,40 @@ do
case "$1" in
-a)
annotate=1
shift
;;
-s)
annotate=1
signed=1
shift
;;
-f)
force=1
shift
;;
-n)
case $2 in
-*) LINES=1 # no argument
case "$#,$2" in
1,* | *,-*)
LINES=1 # no argument
;;
*) shift
LINES=$(expr "$1" : '\([0-9]*\)')
[ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used
;;
esac
shift
;;
-l)
list=1
shift
PATTERN="$1" # select tags by shell pattern, not re
case $# in
0) PATTERN=
;;
*)
PATTERN="$1" # select tags by shell pattern, not re
shift
;;
esac
git rev-parse --symbolic --tags | /usr/bin/sort |
while read TAG
do
@@ -51,12 +63,16 @@ do
[ "$LINES" -le 0 ] && { echo "$TAG"; continue ;}
OBJTYPE=$(git cat-file -t "$TAG")
case $OBJTYPE in
tag) ANNOTATION=$(git cat-file tag "$TAG" |
sed -e '1,/^$/d' \
-e '/^-----BEGIN PGP SIGNATURE-----$/Q' )
printf "%-15s %s\n" "$TAG" "$ANNOTATION" |
sed -e '2,$s/^/ /' \
-e "${LINES}q"
tag)
ANNOTATION=$(git cat-file tag "$TAG" |
sed -e '1,/^$/d' |
sed -n -e "
/^-----BEGIN PGP SIGNATURE-----\$/q
2,\$s/^/ /
p
${LINES}q
")
printf "%-15s %s\n" "$TAG" "$ANNOTATION"
;;
*) echo "$TAG"
;;
@@ -70,7 +86,9 @@ do
if test "$#" = "0"; then
die "error: option -m needs an argument"
else
message="$1"
message_given=1
shift
fi
;;
-F)
@@ -81,13 +99,19 @@ do
else
message="$(cat "$1")"
message_given=1
shift
fi
;;
-u)
annotate=1
signed=1
shift
username="$1"
if test "$#" = "0"; then
die "error: option -u needs an argument"
else
username="$1"
shift
fi
;;
-d)
shift
@@ -122,7 +146,6 @@ do
break
;;
esac
shift
done
[ -n "$list" ] && exit 0

View File

@@ -37,8 +37,9 @@ esac
trap 'rm -f "$GIT_DIR/.tmp-vtag"' 0
git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1
cat "$GIT_DIR/.tmp-vtag" |
sed '/-----BEGIN PGP/Q' |
sed -n -e '
/^-----BEGIN PGP SIGNATURE-----$/q
p
' <"$GIT_DIR/.tmp-vtag" |
gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1
rm -f "$GIT_DIR/.tmp-vtag"

121
git.c
View File

@@ -4,7 +4,7 @@
#include "quote.h"
const char git_usage_string[] =
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
static void prepend_to_path(const char *dir, int len)
{
@@ -32,7 +32,7 @@ static void prepend_to_path(const char *dir, int len)
free(path);
}
static int handle_options(const char*** argv, int* argc)
static int handle_options(const char*** argv, int* argc, int* envchanged)
{
int handled = 0;
@@ -68,14 +68,34 @@ static int handle_options(const char*** argv, int* argc)
usage(git_usage_string);
}
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
handled++;
} else if (!prefixcmp(cmd, "--git-dir=")) {
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) {
if (*argc < 2) {
fprintf(stderr, "No directory given for --work-tree.\n" );
usage(git_usage_string);
}
setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--work-tree=")) {
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
if (envchanged)
*envchanged = 1;
} else {
fprintf(stderr, "Unknown option: %s\n", cmd);
usage(git_usage_string);
@@ -154,7 +174,7 @@ static int split_cmdline(char *cmdline, const char ***argv)
static int handle_alias(int *argcp, const char ***argv)
{
int nongit = 0, ret = 0, saved_errno = errno;
int nongit = 0, envchanged = 0, ret = 0, saved_errno = errno;
const char *subdir;
int count, option_count;
const char** new_argv;
@@ -175,7 +195,11 @@ static int handle_alias(int *argcp, const char ***argv)
alias_string + 1, alias_command);
}
count = split_cmdline(alias_string, &new_argv);
option_count = handle_options(&new_argv, &count);
option_count = handle_options(&new_argv, &count, &envchanged);
if (envchanged)
die("alias '%s' changes environment variables\n"
"You can use '!git' in the alias to do this.",
alias_command);
memmove(new_argv - option_count, new_argv,
count * sizeof(char *));
new_argv -= option_count;
@@ -218,17 +242,56 @@ const char git_version_string[] = GIT_VERSION;
* require working tree to be present -- anything uses this needs
* RUN_SETUP for reading from the configuration file.
*/
#define NOT_BARE (1<<2)
#define NEED_WORK_TREE (1<<2)
static void handle_internal_command(int argc, const char **argv, char **envp)
struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, const char *);
int option;
};
static int run_command(struct cmd_struct *p, int argc, const char **argv)
{
int status;
struct stat st;
const char *prefix;
prefix = NULL;
if (p->option & RUN_SETUP)
prefix = setup_git_directory();
if (p->option & USE_PAGER)
setup_pager();
if ((p->option & NEED_WORK_TREE) &&
(!is_inside_work_tree() || is_inside_git_dir()))
die("%s must be run in a work tree", p->cmd);
trace_argv_printf(argv, argc, "trace: built-in: git");
status = p->fn(argc, argv, prefix);
if (status)
return status;
/* Somebody closed stdout? */
if (fstat(fileno(stdout), &st))
return 0;
/* Ignore write errors for pipes and sockets.. */
if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
return 0;
/* Check for ENOSPC and EIO errors.. */
if (fflush(stdout))
die("write failure on standard output: %s", strerror(errno));
if (ferror(stdout))
die("unknown write failure on standard output");
if (fclose(stdout))
die("close failed on standard output: %s", strerror(errno));
return 0;
}
static void handle_internal_command(int argc, const char **argv)
{
const char *cmd = argv[0];
static struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, const char *);
int option;
} commands[] = {
{ "add", cmd_add, RUN_SETUP | NOT_BARE },
static struct cmd_struct commands[] = {
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
{ "apply", cmd_apply },
{ "archive", cmd_archive },
@@ -238,9 +301,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "cat-file", cmd_cat_file, RUN_SETUP },
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
{ "check-attr", cmd_check_attr, RUN_SETUP | NOT_BARE },
{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
{ "cherry", cmd_cherry, RUN_SETUP },
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE },
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "config", cmd_config },
{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -268,7 +331,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "mailsplit", cmd_mailsplit },
{ "merge-base", cmd_merge_base, RUN_SETUP },
{ "merge-file", cmd_merge_file },
{ "mv", cmd_mv, RUN_SETUP | NOT_BARE },
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
{ "name-rev", cmd_name_rev, RUN_SETUP },
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
{ "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
@@ -281,9 +344,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "rerere", cmd_rerere, RUN_SETUP },
{ "rev-list", cmd_rev_list, RUN_SETUP },
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
{ "revert", cmd_revert, RUN_SETUP | NOT_BARE },
{ "rm", cmd_rm, RUN_SETUP | NOT_BARE },
{ "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
@@ -320,25 +383,13 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
for (i = 0; i < ARRAY_SIZE(commands); i++) {
struct cmd_struct *p = commands+i;
const char *prefix;
if (strcmp(p->cmd, cmd))
continue;
prefix = NULL;
if (p->option & RUN_SETUP)
prefix = setup_git_directory();
if (p->option & USE_PAGER)
setup_pager();
if ((p->option & NOT_BARE) &&
(is_bare_repository() || is_inside_git_dir()))
die("%s must be run in a work tree", cmd);
trace_argv_printf(argv, argc, "trace: built-in: git");
exit(p->fn(argc, argv, prefix));
exit(run_command(p, argc, argv));
}
}
int main(int argc, const char **argv, char **envp)
int main(int argc, const char **argv)
{
const char *cmd = argv[0] ? argv[0] : "git-help";
char *slash = strrchr(cmd, '/');
@@ -381,14 +432,14 @@ int main(int argc, const char **argv, char **envp)
if (!prefixcmp(cmd, "git-")) {
cmd += 4;
argv[0] = cmd;
handle_internal_command(argc, argv, envp);
handle_internal_command(argc, argv);
die("cannot handle %s internally", cmd);
}
/* Look for flags.. */
argv++;
argc--;
handle_options(&argv, &argc);
handle_options(&argv, &argc, NULL);
if (argc > 0) {
if (!prefixcmp(argv[0], "--"))
argv[0] += 2;
@@ -413,7 +464,7 @@ int main(int argc, const char **argv, char **envp)
while (1) {
/* See if it's an internal command */
handle_internal_command(argc, argv, envp);
handle_internal_command(argc, argv);
/* .. then try the external ones */
execv_git_cmd(argv);

View File

@@ -408,5 +408,6 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
shown = 1;
}
opt->loginfo = NULL;
maybe_flush_or_die(stdout, "stdout");
return shown;
}

234
setup.c
View File

@@ -132,7 +132,7 @@ void verify_non_filename(const char *prefix, const char *arg)
const char *name;
struct stat st;
if (is_inside_git_dir())
if (!is_inside_work_tree() || is_inside_git_dir())
return;
if (*arg == '-')
return; /* flag */
@@ -211,42 +211,104 @@ static int inside_git_dir = -1;
int is_inside_git_dir(void)
{
if (inside_git_dir < 0) {
char buffer[1024];
if (inside_git_dir >= 0)
return inside_git_dir;
die("BUG: is_inside_git_dir called before setup_git_directory");
}
if (is_bare_repository())
return (inside_git_dir = 1);
if (getcwd(buffer, sizeof(buffer))) {
const char *git_dir = get_git_dir(), *cwd = buffer;
while (*git_dir && *git_dir == *cwd) {
git_dir++;
cwd++;
}
inside_git_dir = !*git_dir;
} else
inside_git_dir = 0;
static int inside_work_tree = -1;
int is_inside_work_tree(void)
{
if (inside_git_dir >= 0)
return inside_work_tree;
die("BUG: is_inside_work_tree called before setup_git_directory");
}
static char *gitworktree_config;
static int git_setup_config(const char *var, const char *value)
{
if (!strcmp(var, "core.worktree")) {
if (gitworktree_config)
strlcpy(gitworktree_config, value, PATH_MAX);
return 0;
}
return inside_git_dir;
return git_default_config(var, value);
}
const char *setup_git_directory_gently(int *nongit_ok)
{
static char cwd[PATH_MAX+1];
const char *gitdirenv;
int len, offset;
int minoffset = 0;
char worktree[PATH_MAX+1], gitdir[PATH_MAX+1];
const char *gitdirenv, *gitworktree;
int wt_rel_gitdir = 0;
/*
* If GIT_DIR is set explicitly, we're not going
* to do any discovery, but we still do repository
* validation.
*/
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
if (gitdirenv) {
if (PATH_MAX - 40 < strlen(gitdirenv))
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
if (is_git_directory(gitdirenv))
if (!gitdirenv) {
int len, offset;
int minoffset = 0;
#ifdef __MINGW32__
if (!getcwd(cwd, sizeof(cwd)-1) || !(cwd[0] == '/' || cwd[1] == ':'))
die("Unable to read current working directory");
if (cwd[1] == ':')
minoffset = 2;
#else
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
die("Unable to read current working directory");
#endif
offset = len = strlen(cwd);
for (;;) {
if (is_git_directory(".git"))
break;
if (offset == 0) {
offset = -1;
break;
}
chdir("..");
while (offset > minoffset && cwd[--offset] != '/')
; /* do nothing */
}
if (offset >= 0) {
inside_work_tree = 1;
git_config(git_default_config);
if (offset == len) {
inside_git_dir = 0;
return NULL;
}
cwd[len++] = '/';
cwd[len] = '\0';
inside_git_dir = !prefixcmp(cwd + offset + 1, ".git/");
return cwd + offset + 1;
}
if (chdir(cwd))
die("Cannot come back to cwd");
if (!is_git_directory(".")) {
if (nongit_ok) {
*nongit_ok = 1;
return NULL;
}
die("Not a git repository");
}
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
if (!gitdirenv)
die("getenv after setenv failed");
}
if (PATH_MAX - 40 < strlen(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
return NULL;
}
die("$%s too big", GIT_DIR_ENVIRONMENT);
}
if (!is_git_directory(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
return NULL;
@@ -254,50 +316,94 @@ const char *setup_git_directory_gently(int *nongit_ok)
die("Not a git repository: '%s'", gitdirenv);
}
#ifdef __MINGW32__
if (!getcwd(cwd, sizeof(cwd)-1) || !(cwd[0] == '/' || cwd[1] == ':'))
die("Unable to read current working directory");
if (cwd[1] == ':')
minoffset = 2;
#else
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
die("Unable to read current working directory");
#endif
if (chdir(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
return NULL;
}
die("Cannot change directory to $%s '%s'",
GIT_DIR_ENVIRONMENT, gitdirenv);
}
if (!getcwd(gitdir, sizeof(gitdir)-1) || gitdir[0] != '/')
die("Unable to read current working directory");
if (chdir(cwd))
die("Cannot come back to cwd");
offset = len = strlen(cwd);
for (;;) {
if (is_git_directory(".git"))
break;
chdir("..");
do {
if (offset <= minoffset) {
if (is_git_directory(cwd)) {
if (chdir(cwd))
die("Cannot come back to cwd");
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
inside_git_dir = 1;
return NULL;
}
if (nongit_ok) {
if (chdir(cwd))
die("Cannot come back to cwd");
*nongit_ok = 1;
return NULL;
}
die("Not a git repository");
/*
* In case there is a work tree we may change the directory,
* therefore make GIT_DIR an absolute path.
*/
if (gitdirenv[0] != '/') {
setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
if (!gitdirenv)
die("getenv after setenv failed");
if (PATH_MAX - 40 < strlen(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
return NULL;
}
} while (offset > minoffset && cwd[--offset] != '/');
die("$%s too big after expansion to absolute path",
GIT_DIR_ENVIRONMENT);
}
}
if (offset == len)
return NULL;
strcat(cwd, "/");
strcat(gitdir, "/");
inside_git_dir = !prefixcmp(cwd, gitdir);
/* Make "offset" point to past the '/', and add a '/' at the end */
offset++;
cwd[len++] = '/';
cwd[len] = 0;
inside_git_dir = !prefixcmp(cwd + offset, ".git/");
return cwd + offset;
gitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);
if (!gitworktree) {
gitworktree_config = worktree;
worktree[0] = '\0';
}
git_config(git_setup_config);
if (!gitworktree) {
gitworktree_config = NULL;
if (worktree[0])
gitworktree = worktree;
if (gitworktree && gitworktree[0] != '/')
wt_rel_gitdir = 1;
}
if (wt_rel_gitdir && chdir(gitdirenv))
die("Cannot change directory to $%s '%s'",
GIT_DIR_ENVIRONMENT, gitdirenv);
if (gitworktree && chdir(gitworktree)) {
if (nongit_ok) {
if (wt_rel_gitdir && chdir(cwd))
die("Cannot come back to cwd");
*nongit_ok = 1;
return NULL;
}
if (wt_rel_gitdir)
die("Cannot change directory to working tree '%s'"
" from $%s", gitworktree, GIT_DIR_ENVIRONMENT);
else
die("Cannot change directory to working tree '%s'",
gitworktree);
}
if (!getcwd(worktree, sizeof(worktree)-1) || worktree[0] != '/')
die("Unable to read current working directory");
strcat(worktree, "/");
inside_work_tree = !prefixcmp(cwd, worktree);
if (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&
strcmp(worktree, gitdir)) {
inside_git_dir = 0;
}
if (!inside_work_tree) {
if (chdir(cwd))
die("Cannot come back to cwd");
return NULL;
}
if (!strcmp(cwd, worktree))
return NULL;
return cwd+strlen(worktree);
}
int git_config_perm(const char *var, const char *value)

355
t/t0030-stripspace.sh Executable file
View File

@@ -0,0 +1,355 @@
#!/bin/sh
#
# Copyright (c) 2007 Carlos Rica
#
test_description='git-stripspace'
. ./test-lib.sh
t40='A quick brown fox jumps over the lazy do'
s40=' '
sss="$s40$s40$s40$s40$s40$s40$s40$s40$s40$s40" # 400
ttt="$t40$t40$t40$t40$t40$t40$t40$t40$t40$t40" # 400
test_expect_success \
'long lines without spaces should be unchanged' '
echo "$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual &&
echo "$ttt$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual &&
echo "$ttt$ttt$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual &&
echo "$ttt$ttt$ttt$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual
'
test_expect_success \
'lines with spaces at the beginning should be unchanged' '
echo "$sss$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual &&
echo "$sss$sss$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual &&
echo "$sss$sss$sss$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual
'
test_expect_success \
'lines with intermediate spaces should be unchanged' '
echo "$ttt$sss$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual &&
echo "$ttt$sss$sss$ttt" >expect &&
git-stripspace <expect >actual &&
git diff expect actual
'
test_expect_success \
'consecutive blank lines should be unified' '
printf "$ttt\n\n$ttt\n" > expect &&
printf "$ttt\n\n\n\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt\n\n$ttt\n" > expect &&
printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n\n$ttt\n" > expect &&
printf "$ttt\n\n\n\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n\n$ttt$ttt\n" > expect &&
printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git-stripspace >actual &&
git diff expect actual
'
test_expect_success \
'consecutive blank lines at the beginning should be removed' '
printf "" > expect &&
printf "\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "$sss\n$sss\n$sss\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "$sss$sss\n$sss\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "\n$sss\n$sss$sss\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "$sss$sss$sss$sss\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "\n$sss$sss$sss$sss\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "" > expect &&
printf "\n\n$sss$sss$sss$sss\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "\n\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt\n" > expect &&
printf "\n\n\n$ttt$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt$ttt\n" > expect &&
printf "\n\n\n$ttt$ttt$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt$ttt$ttt\n" > expect &&
printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$sss\n$sss\n$sss\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "\n$sss\n$sss$sss\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$sss$sss\n$sss\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$sss$sss$sss\n\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "\n$sss$sss$sss\n\n$ttt\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "\n\n$sss$sss$sss\n$ttt\n" | git-stripspace >actual &&
git diff expect actual
'
test_expect_success \
'consecutive blank lines at the end should be removed' '
printf "$ttt\n" > expect &&
printf "$ttt\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt\n" > expect &&
printf "$ttt$ttt\n\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt$ttt\n" > expect &&
printf "$ttt$ttt$ttt\n\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt$ttt$ttt\n" > expect &&
printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n$sss\n$sss\n$sss\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n\n$sss\n$sss$sss\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n$sss$sss\n$sss\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n$sss$sss$sss\n\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n\n$sss$sss$sss\n\n" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" > expect &&
printf "$ttt\n\n\n$sss$sss$sss\n" | git-stripspace >actual &&
git diff expect actual
'
test_expect_success \
'text without newline at end should end with newline' '
test `printf "$ttt" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$ttt" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$ttt$ttt" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$ttt$ttt$ttt" | git-stripspace | wc -l` -gt 0
'
# text plus spaces at the end:
test_expect_success \
'text plus spaces without newline at end should end with newline' '
test `printf "$ttt$sss" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$ttt$sss" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$ttt$ttt$sss" | git-stripspace | wc -l` -gt 0
test `printf "$ttt$sss$sss" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$ttt$sss$sss" | git-stripspace | wc -l` -gt 0 &&
test `printf "$ttt$sss$sss$sss" | git-stripspace | wc -l` -gt 0
'
test_expect_failure \
'text plus spaces without newline at end should not show spaces' '
printf "$ttt$sss" | git-stripspace | grep -q " " ||
printf "$ttt$ttt$sss" | git-stripspace | grep -q " " ||
printf "$ttt$ttt$ttt$sss" | git-stripspace | grep -q " " ||
printf "$ttt$sss$sss" | git-stripspace | grep -q " " ||
printf "$ttt$ttt$sss$sss" | git-stripspace | grep -q " " ||
printf "$ttt$sss$sss$sss" | git-stripspace | grep -q " "
'
test_expect_success \
'text plus spaces without newline should show the correct lines' '
printf "$ttt\n" >expect &&
printf "$ttt$sss" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" >expect &&
printf "$ttt$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt\n" >expect &&
printf "$ttt$sss$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt\n" >expect &&
printf "$ttt$ttt$sss" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt\n" >expect &&
printf "$ttt$ttt$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
printf "$ttt$ttt$ttt\n" >expect &&
printf "$ttt$ttt$ttt$sss" | git-stripspace >actual &&
git diff expect actual
'
test_expect_failure \
'text plus spaces at end should not show spaces' '
echo "$ttt$sss" | git-stripspace | grep -q " " ||
echo "$ttt$ttt$sss" | git-stripspace | grep -q " " ||
echo "$ttt$ttt$ttt$sss" | git-stripspace | grep -q " " ||
echo "$ttt$sss$sss" | git-stripspace | grep -q " " ||
echo "$ttt$ttt$sss$sss" | git-stripspace | grep -q " " ||
echo "$ttt$sss$sss$sss" | git-stripspace | grep -q " "
'
test_expect_success \
'text plus spaces at end should be cleaned and newline must remain' '
echo "$ttt" >expect &&
echo "$ttt$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$ttt" >expect &&
echo "$ttt$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$ttt" >expect &&
echo "$ttt$sss$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$ttt$ttt" >expect &&
echo "$ttt$ttt$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$ttt$ttt" >expect &&
echo "$ttt$ttt$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$ttt$ttt$ttt" >expect &&
echo "$ttt$ttt$ttt$sss" | git-stripspace >actual &&
git diff expect actual
'
# spaces only:
test_expect_success \
'spaces with newline at end should be replaced with empty string' '
printf "" >expect &&
echo | git-stripspace >actual &&
git diff expect actual &&
echo "$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$sss$sss$sss" | git-stripspace >actual &&
git diff expect actual &&
echo "$sss$sss$sss$sss" | git-stripspace >actual &&
git diff expect actual
'
test_expect_failure \
'spaces without newline at end should not show spaces' '
printf "" | git-stripspace | grep -q " " ||
printf "$sss" | git-stripspace | grep -q " " ||
printf "$sss$sss" | git-stripspace | grep -q " " ||
printf "$sss$sss$sss" | git-stripspace | grep -q " " ||
printf "$sss$sss$sss$sss" | git-stripspace | grep -q " "
'
test_expect_success \
'spaces without newline at end should be replaced with empty string' '
printf "" >expect &&
printf "" | git-stripspace >actual &&
git diff expect actual
printf "$sss$sss" | git-stripspace >actual &&
git diff expect actual
printf "$sss$sss$sss" | git-stripspace >actual &&
git diff expect actual
printf "$sss$sss$sss$sss" | git-stripspace >actual &&
git diff expect actual
'
test_done

View File

@@ -471,11 +471,57 @@ test_expect_success bool '
done &&
cmp expect result'
test_expect_failure 'invalid bool' '
test_expect_failure 'invalid bool (--get)' '
git-config bool.nobool foobar &&
git-config --bool --get bool.nobool'
test_expect_failure 'invalid bool (set)' '
git-config --bool bool.nobool foobar'
rm .git/config
cat > expect <<\EOF
[bool]
true1 = true
true2 = true
true3 = true
true4 = true
false1 = false
false2 = false
false3 = false
false4 = false
EOF
test_expect_success 'set --bool' '
git-config --bool bool.true1 01 &&
git-config --bool bool.true2 -1 &&
git-config --bool bool.true3 YeS &&
git-config --bool bool.true4 true &&
git-config --bool bool.false1 000 &&
git-config --bool bool.false2 "" &&
git-config --bool bool.false3 nO &&
git-config --bool bool.false4 FALSE &&
cmp expect .git/config'
rm .git/config
cat > expect <<\EOF
[int]
val1 = 1
val2 = -1
val3 = 5242880
EOF
test_expect_success 'set --int' '
git-config --int int.val1 01 &&
git-config --int int.val2 -1 &&
git-config --int int.val3 5m &&
cmp expect .git/config'
rm .git/config
git-config quote.leading " test"

77
t/t1500-rev-parse.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/sh
test_description='test git rev-parse'
. ./test-lib.sh
test_rev_parse() {
name=$1
shift
test_expect_success "$name: is-bare-repository" \
"test '$1' = \"\$(git rev-parse --is-bare-repository)\""
shift
[ $# -eq 0 ] && return
test_expect_success "$name: is-inside-git-dir" \
"test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
shift
[ $# -eq 0 ] && return
test_expect_success "$name: is-inside-work-tree" \
"test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
shift
[ $# -eq 0 ] && return
test_expect_success "$name: prefix" \
"test '$1' = \"\$(git rev-parse --show-prefix)\""
shift
[ $# -eq 0 ] && return
}
test_rev_parse toplevel false false true ''
cd .git || exit 1
test_rev_parse .git/ false true true .git/
cd objects || exit 1
test_rev_parse .git/objects/ false true true .git/objects/
cd ../.. || exit 1
mkdir -p sub/dir || exit 1
cd sub/dir || exit 1
test_rev_parse subdirectory false false true sub/dir/
cd ../.. || exit 1
git config core.bare true
test_rev_parse 'core.bare = true' true false true
git config --unset core.bare
test_rev_parse 'core.bare undefined' false false true
mkdir work || exit 1
cd work || exit 1
export GIT_DIR=../.git
export GIT_CONFIG="$GIT_DIR"/config
git config core.bare false
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 true ''
git config --unset core.bare
test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
mv ../.git ../repo.git || exit 1
export GIT_DIR=../repo.git
export GIT_CONFIG="$GIT_DIR"/config
git config core.bare false
test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''
git config core.bare true
test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''
git config --unset core.bare
test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''
test_done

92
t/t1501-worktree.sh Executable file
View File

@@ -0,0 +1,92 @@
#!/bin/sh
test_description='test separate work tree'
. ./test-lib.sh
test_rev_parse() {
name=$1
shift
test_expect_success "$name: is-bare-repository" \
"test '$1' = \"\$(git rev-parse --is-bare-repository)\""
shift
[ $# -eq 0 ] && return
test_expect_success "$name: is-inside-git-dir" \
"test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
shift
[ $# -eq 0 ] && return
test_expect_success "$name: is-inside-work-tree" \
"test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
shift
[ $# -eq 0 ] && return
test_expect_success "$name: prefix" \
"test '$1' = \"\$(git rev-parse --show-prefix)\""
shift
[ $# -eq 0 ] && return
}
mkdir -p work/sub/dir || exit 1
mv .git repo.git || exit 1
say "core.worktree = relative path"
export GIT_DIR=repo.git
export GIT_CONFIG=$GIT_DIR/config
unset GIT_WORK_TREE
git config core.worktree ../work
test_rev_parse 'outside' false false false
cd work || exit 1
export GIT_DIR=../repo.git
export GIT_CONFIG=$GIT_DIR/config
test_rev_parse 'inside' false false true ''
cd sub/dir || exit 1
export GIT_DIR=../../../repo.git
export GIT_CONFIG=$GIT_DIR/config
test_rev_parse 'subdirectory' false false true sub/dir/
cd ../../.. || exit 1
say "core.worktree = absolute path"
export GIT_DIR=$(pwd)/repo.git
export GIT_CONFIG=$GIT_DIR/config
git config core.worktree "$(pwd)/work"
test_rev_parse 'outside' false false false
cd work || exit 1
test_rev_parse 'inside' false false true ''
cd sub/dir || exit 1
test_rev_parse 'subdirectory' false false true sub/dir/
cd ../../.. || exit 1
say "GIT_WORK_TREE=relative path (override core.worktree)"
export GIT_DIR=$(pwd)/repo.git
export GIT_CONFIG=$GIT_DIR/config
git config core.worktree non-existent
export GIT_WORK_TREE=work
test_rev_parse 'outside' false false false
cd work || exit 1
export GIT_WORK_TREE=.
test_rev_parse 'inside' false false true ''
cd sub/dir || exit 1
export GIT_WORK_TREE=../..
test_rev_parse 'subdirectory' false false true sub/dir/
cd ../../.. || exit 1
mv work repo.git/work
say "GIT_WORK_TREE=absolute path, work tree below git dir"
export GIT_DIR=$(pwd)/repo.git
export GIT_CONFIG=$GIT_DIR/config
export GIT_WORK_TREE=$(pwd)/repo.git/work
test_rev_parse 'outside' false false false
cd repo.git || exit 1
test_rev_parse 'in repo.git' false true false
cd objects || exit 1
test_rev_parse 'in repo.git/objects' false true false
cd ../work || exit 1
test_rev_parse 'in repo.git/work' false false true ''
cd sub/dir || exit 1
test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/
cd ../../../.. || exit 1
test_done

686
t/t7004-tag.sh Executable file
View File

@@ -0,0 +1,686 @@
#!/bin/sh
#
# Copyright (c) 2007 Carlos Rica
#
test_description='git-tag
Basic tests for operations with tags.'
. ./test-lib.sh
# creating and listing lightweight tags:
tag_exists () {
git show-ref --quiet --verify refs/tags/"$1"
}
# 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 output nothing' \
'test `git-tag -l | wc -l` -eq 0'
test_expect_failure 'looking for a tag in an empty tree should fail' \
'tag_exists mytag'
test_expect_success 'creating a tag in an empty tree should fail' '
! git-tag mynotag &&
! tag_exists mynotag
'
test_expect_success 'creating a tag for HEAD in an empty tree should fail' '
! git-tag mytaghead HEAD &&
! tag_exists mytaghead
'
test_expect_success 'creating a tag for an unknown revision should fail' '
! git-tag mytagnorev aaaaaaaaaaa &&
! tag_exists mytagnorev
'
# commit used in the tests, test_tick is also called here to freeze the date:
test_expect_success 'creating a tag using default HEAD should succeed' '
test_tick &&
echo foo >foo &&
git add foo &&
git commit -m Foo &&
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 output that tag' \
'test `git-tag -l` = mytag'
# pattern matching:
test_expect_success 'listing a tag using a matching pattern should succeed' \
'git-tag -l mytag'
test_expect_success \
'listing a tag using a matching pattern should output that tag' \
'test `git-tag -l mytag` = mytag'
# todo: git tag -l now returns always zero, when fixed, change this test
test_expect_success \
'listing tags using a non-matching pattern should suceed' \
'git-tag -l xxx'
test_expect_success \
'listing tags using a non-matching pattern should output nothing' \
'test `git-tag -l xxx | wc -l` -eq 0'
# special cases for creating tags:
test_expect_failure \
'trying to create a tag with the name of one existing should fail' \
'git tag mytag'
test_expect_success \
'trying to create a tag with a non-valid name should fail' '
test `git-tag -l | wc -l` -eq 1 &&
! git tag "" &&
! git tag .othertag &&
! git tag "other tag" &&
! git tag "othertag^" &&
! git tag "other~tag" &&
test `git-tag -l | wc -l` -eq 1
'
test_expect_success 'creating a tag using HEAD directly should succeed' '
git tag myhead HEAD &&
tag_exists myhead
'
# deleting tags:
test_expect_success 'trying to delete an unknown tag should fail' '
! tag_exists unknown-tag &&
! git-tag -d unknown-tag
'
cat >expect <<EOF
myhead
mytag
EOF
test_expect_success \
'trying to delete tags without params should succeed and do nothing' '
git tag -l > actual && git diff expect actual &&
git-tag -d &&
git tag -l > actual && git diff expect actual
'
test_expect_success \
'deleting two existing tags in one command should succeed' '
tag_exists mytag &&
tag_exists myhead &&
git-tag -d mytag myhead &&
! tag_exists mytag &&
! tag_exists myhead
'
test_expect_success \
'creating a tag with the name of another deleted one should succeed' '
! tag_exists mytag &&
git-tag mytag &&
tag_exists mytag
'
test_expect_success \
'trying to delete two tags, existing and not, should fail in the 2nd' '
tag_exists mytag &&
! tag_exists myhead &&
! git-tag -d mytag anothertag &&
! tag_exists mytag &&
! tag_exists myhead
'
test_expect_failure 'trying to delete an already deleted tag should fail' \
'git-tag -d mytag'
# listing various tags with pattern matching:
cat >expect <<EOF
a1
aa1
cba
t210
t211
v0.2.1
v1.0
v1.0.1
v1.1.3
EOF
test_expect_success 'listing all tags should print them ordered' '
git tag v1.0.1 &&
git tag t211 &&
git tag aa1 &&
git tag v0.2.1 &&
git tag v1.1.3 &&
git tag cba &&
git tag a1 &&
git tag v1.0 &&
git tag t210 &&
git tag -l > actual
git diff expect actual
'
cat >expect <<EOF
a1
aa1
cba
EOF
test_expect_success \
'listing tags with substring as pattern must print those matching' '
git-tag -l a > actual &&
git-diff expect actual
'
cat >expect <<EOF
v0.2.1
v1.0.1
v1.1.3
EOF
test_expect_success \
'listing tags with substring as pattern must print those matching' '
git-tag -l .1 > actual &&
git-diff expect actual
'
cat >expect <<EOF
t210
t211
EOF
test_expect_success \
'listing tags with substring as pattern must print those matching' '
git-tag -l t21 > actual &&
git-diff expect actual
'
cat >expect <<EOF
a1
aa1
EOF
test_expect_success \
'listing tags using a name as pattern must print those matching' '
git-tag -l a1 > actual &&
git-diff expect actual
'
cat >expect <<EOF
v1.0
v1.0.1
EOF
test_expect_success \
'listing tags using a name as pattern must print those matching' '
git-tag -l v1.0 > actual &&
git-diff expect actual
'
cat >expect <<EOF
v1.1.3
EOF
test_expect_success \
'listing tags with ? in the pattern should print those matching' '
git-tag -l "1.1?" > actual &&
git-diff expect actual
'
>expect
test_expect_success \
'listing tags using v.* should print nothing because none have v.' '
git-tag -l "v.*" > actual &&
git-diff expect actual
'
cat >expect <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
EOF
test_expect_success \
'listing tags using v* should print only those having v' '
git-tag -l "v*" > actual &&
git-diff expect actual
'
# creating and verifying lightweight tags:
test_expect_success \
'a non-annotated tag created without parameters should point to HEAD' '
git-tag non-annotated-tag &&
test $(git-cat-file -t non-annotated-tag) = commit &&
test $(git-rev-parse non-annotated-tag) = $(git-rev-parse HEAD)
'
test_expect_failure 'trying to verify an unknown tag should fail' \
'git-tag -v unknown-tag'
test_expect_failure \
'trying to verify a non-annotated and non-signed tag should fail' \
'git-tag -v non-annotated-tag'
# creating annotated tags:
get_tag_msg () {
git cat-file tag "$1" | sed -e "/BEGIN PGP/q"
}
# run test_tick before committing always gives the time in that timezone
get_tag_header () {
cat <<EOF
object $2
type $3
tag $1
tagger C O Mitter <committer@example.com> $4 -0700
EOF
}
commit=$(git rev-parse HEAD)
time=$test_tick
get_tag_header annotated-tag $commit commit $time >expect
echo "A message" >>expect
test_expect_success \
'creating an annotated tag with -m message should succeed' '
git-tag -m "A message" annotated-tag &&
get_tag_msg annotated-tag >actual &&
git diff expect actual
'
cat >msgfile <<EOF
Another message
in a file.
EOF
get_tag_header file-annotated-tag $commit commit $time >expect
cat msgfile >>expect
test_expect_success \
'creating an annotated tag with -F messagefile should succeed' '
git-tag -F msgfile file-annotated-tag &&
get_tag_msg file-annotated-tag >actual &&
git diff expect actual
'
# blank and empty messages:
get_tag_header empty-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with an empty -m message should succeed' '
git-tag -m "" empty-annotated-tag &&
get_tag_msg empty-annotated-tag >actual &&
git diff expect actual
'
>emptyfile
get_tag_header emptyfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with an empty -F messagefile should succeed' '
git-tag -F emptyfile emptyfile-annotated-tag &&
get_tag_msg emptyfile-annotated-tag >actual &&
git diff expect actual
'
printf '\n\n \n\t\nLeading blank lines\n' >blanksfile
printf '\n\t \t \nRepeated blank lines\n' >>blanksfile
printf '\n\n\nTrailing spaces \t \n' >>blanksfile
printf '\nTrailing blank lines\n\n\t \n\n' >>blanksfile
get_tag_header blanks-annotated-tag $commit commit $time >expect
cat >>expect <<EOF
Leading blank lines
Repeated blank lines
Trailing spaces
Trailing blank lines
EOF
test_expect_success \
'extra blanks in the message for an annotated tag should be removed' '
git-tag -F blanksfile blanks-annotated-tag &&
get_tag_msg blanks-annotated-tag >actual &&
git diff expect actual
'
get_tag_header blank-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with blank -m message with spaces should succeed' '
git-tag -m " " blank-annotated-tag &&
get_tag_msg blank-annotated-tag >actual &&
git diff expect actual
'
echo ' ' >blankfile
echo '' >>blankfile
echo ' ' >>blankfile
get_tag_header blankfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with blank -F messagefile with spaces should succeed' '
git-tag -F blankfile blankfile-annotated-tag &&
get_tag_msg blankfile-annotated-tag >actual &&
git diff expect actual
'
printf ' ' >blanknonlfile
get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with -F file of spaces and no newline should succeed' '
git-tag -F blanknonlfile blanknonlfile-annotated-tag &&
get_tag_msg blanknonlfile-annotated-tag >actual &&
git diff expect actual
'
# messages with commented lines:
cat >commentsfile <<EOF
# A comment
############
The message.
############
One line.
# commented lines
# commented lines
Another line.
# comments
Last line.
EOF
get_tag_header comments-annotated-tag $commit commit $time >expect
cat >>expect <<EOF
The message.
One line.
Another line.
Last line.
EOF
test_expect_success \
'creating a tag using a -F messagefile with #comments should succeed' '
git-tag -F commentsfile comments-annotated-tag &&
get_tag_msg comments-annotated-tag >actual &&
git diff expect actual
'
get_tag_header comment-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with a #comment in the -m message should succeed' '
git-tag -m "#comment" comment-annotated-tag &&
get_tag_msg comment-annotated-tag >actual &&
git diff expect actual
'
echo '#comment' >commentfile
echo '' >>commentfile
echo '####' >>commentfile
get_tag_header commentfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with #comments in the -F messagefile should succeed' '
git-tag -F commentfile commentfile-annotated-tag &&
get_tag_msg commentfile-annotated-tag >actual &&
git diff expect actual
'
printf '#comment' >commentnonlfile
get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with a file of #comment and no newline should succeed' '
git-tag -F commentnonlfile commentnonlfile-annotated-tag &&
get_tag_msg commentnonlfile-annotated-tag >actual &&
git diff expect actual
'
# trying to verify annotated non-signed tags:
test_expect_success \
'trying to verify an annotated non-signed tag should fail' '
tag_exists annotated-tag &&
! git-tag -v annotated-tag
'
test_expect_success \
'trying to verify a file-annotated non-signed tag should fail' '
tag_exists file-annotated-tag &&
! git-tag -v file-annotated-tag
'
# creating and verifying signed tags:
gpg --version >/dev/null
if [ $? -eq 127 ]; then
echo "Skipping signed tags tests, because gpg was not found"
test_done
exit
fi
# key generation info: gpg --homedir t/t7004 --gen-key
# Type DSA and Elgamal, size 2048 bits, no expiration date.
# Name and email: C O Mitter <committer@example.com>
# No password given, to enable non-interactive operation.
cp -R ../t7004 ./gpghome
chmod 0700 gpghome
export GNUPGHOME="$(pwd)/gpghome"
get_tag_header signed-tag $commit commit $time >expect
echo 'A signed tag message' >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success 'creating a signed tag with -m message should succeed' '
git-tag -s -m "A signed tag message" signed-tag &&
get_tag_msg signed-tag >actual &&
git-diff expect actual
'
test_expect_success 'verifying a signed tag should succeed' \
'git-tag -v 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/" |
git mktag) &&
git tag forged-tag $forged &&
! git-tag -v forged-tag
'
# blank and empty messages for signed tags:
get_tag_header empty-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with an empty -m message should succeed' '
git-tag -s -m "" empty-signed-tag &&
get_tag_msg empty-signed-tag >actual &&
git diff expect actual &&
git-tag -v empty-signed-tag
'
>sigemptyfile
get_tag_header emptyfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with an empty -F messagefile should succeed' '
git-tag -s -F sigemptyfile emptyfile-signed-tag &&
get_tag_msg emptyfile-signed-tag >actual &&
git diff expect actual &&
git-tag -v emptyfile-signed-tag
'
printf '\n\n \n\t\nLeading blank lines\n' > sigblanksfile
printf '\n\t \t \nRepeated blank lines\n' >>sigblanksfile
printf '\n\n\nTrailing spaces \t \n' >>sigblanksfile
printf '\nTrailing blank lines\n\n\t \n\n' >>sigblanksfile
get_tag_header blanks-signed-tag $commit commit $time >expect
cat >>expect <<EOF
Leading blank lines
Repeated blank lines
Trailing spaces
Trailing blank lines
EOF
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'extra blanks in the message for a signed tag should be removed' '
git-tag -s -F sigblanksfile blanks-signed-tag &&
get_tag_msg blanks-signed-tag >actual &&
git diff expect actual &&
git-tag -v blanks-signed-tag
'
get_tag_header blank-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with a blank -m message should succeed' '
git-tag -s -m " " blank-signed-tag &&
get_tag_msg blank-signed-tag >actual &&
git diff expect actual &&
git-tag -v blank-signed-tag
'
echo ' ' >sigblankfile
echo '' >>sigblankfile
echo ' ' >>sigblankfile
get_tag_header blankfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with blank -F file with spaces should succeed' '
git-tag -s -F sigblankfile blankfile-signed-tag &&
get_tag_msg blankfile-signed-tag >actual &&
git diff expect actual &&
git-tag -v blankfile-signed-tag
'
printf ' ' >sigblanknonlfile
get_tag_header blanknonlfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with spaces and no newline should succeed' '
git-tag -s -F sigblanknonlfile blanknonlfile-signed-tag &&
get_tag_msg blanknonlfile-signed-tag >actual &&
git diff expect actual &&
git-tag -v signed-tag
'
# messages with commented lines for signed tags:
cat >sigcommentsfile <<EOF
# A comment
############
The message.
############
One line.
# commented lines
# commented lines
Another line.
# comments
Last line.
EOF
get_tag_header comments-signed-tag $commit commit $time >expect
cat >>expect <<EOF
The message.
One line.
Another line.
Last line.
EOF
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with a -F file with #comments should succeed' '
git-tag -s -F sigcommentsfile comments-signed-tag &&
get_tag_msg comments-signed-tag >actual &&
git diff expect actual &&
git-tag -v comments-signed-tag
'
get_tag_header comment-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with #commented -m message should succeed' '
git-tag -s -m "#comment" comment-signed-tag &&
get_tag_msg comment-signed-tag >actual &&
git diff expect actual &&
git-tag -v comment-signed-tag
'
echo '#comment' >sigcommentfile
echo '' >>sigcommentfile
echo '####' >>sigcommentfile
get_tag_header commentfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with #commented -F messagefile should succeed' '
git-tag -s -F sigcommentfile commentfile-signed-tag &&
get_tag_msg commentfile-signed-tag >actual &&
git diff expect actual &&
git-tag -v commentfile-signed-tag
'
printf '#comment' >sigcommentnonlfile
get_tag_header commentnonlfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag with a #comment and no newline should succeed' '
git-tag -s -F sigcommentnonlfile commentnonlfile-signed-tag &&
get_tag_msg commentnonlfile-signed-tag >actual &&
git diff expect actual &&
git-tag -v commentnonlfile-signed-tag
'
# tags pointing to objects different from commits:
tree=$(git rev-parse HEAD^{tree})
blob=$(git rev-parse HEAD:foo)
tag=$(git rev-parse signed-tag)
get_tag_header tree-signed-tag $tree tree $time >expect
echo "A message for a tree" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag pointing to a tree should succeed' '
git-tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} &&
get_tag_msg tree-signed-tag >actual &&
git diff expect actual
'
get_tag_header blob-signed-tag $blob blob $time >expect
echo "A message for a blob" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag pointing to a blob should succeed' '
git-tag -s -m "A message for a blob" blob-signed-tag HEAD:foo &&
get_tag_msg blob-signed-tag >actual &&
git diff expect actual
'
get_tag_header tag-signed-tag $tag tag $time >expect
echo "A message for another tag" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success \
'creating a signed tag pointing to another tag should succeed' '
git-tag -s -m "A message for another tag" tag-signed-tag signed-tag &&
get_tag_msg tag-signed-tag >actual &&
git diff expect actual
'
# try to verify without gpg:
rm -rf gpghome
test_expect_failure \
'verify signed tag fails when public key is not present' \
'git-tag -v signed-tag'
test_done

BIN
t/t7004/pubring.gpg Normal file

Binary file not shown.

BIN
t/t7004/random_seed Normal file

Binary file not shown.

BIN
t/t7004/secring.gpg Normal file

Binary file not shown.

View File

@@ -38,7 +38,7 @@ echo >empty &&
git commit -q -m "First Commit" &&
git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
GIT_DIR="$SERVERDIR" git config --bool gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
exit 1
# note that cvs doesn't accept absolute pathnames
@@ -255,7 +255,7 @@ rm -fr "$SERVERDIR"
cd "$WORKDIR" &&
git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
GIT_DIR="$SERVERDIR" git config --bool gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
exit 1
test_expect_success 'cvs update (create new file)' \

View File

@@ -26,6 +26,7 @@ GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
unset GIT_DIFF_OPTS
unset GIT_DIR
unset GIT_WORK_TREE
unset GIT_EXTERNAL_DIFF
unset GIT_INDEX_FILE
unset GIT_OBJECT_DIRECTORY

View File

@@ -1,5 +1,45 @@
#include "cache.h"
/*
* Some cases use stdio, but want to flush after the write
* to get error handling (and to get better interactive
* behaviour - not buffering excessively).
*
* Of course, if the flush happened within the write itself,
* we've already lost the error code, and cannot report it any
* more. So we just ignore that case instead (and hope we get
* the right error code on the flush).
*
* If the file handle is stdout, and stdout is a file, then skip the
* flush entirely since it's not needed.
*/
void maybe_flush_or_die(FILE *f, const char *desc)
{
static int skip_stdout_flush = -1;
struct stat st;
char *cp;
if (f == stdout) {
if (skip_stdout_flush < 0) {
cp = getenv("GIT_FLUSH");
if (cp)
skip_stdout_flush = (atoi(cp) == 0);
else if ((fstat(fileno(stdout), &st) == 0) &&
S_ISREG(st.st_mode))
skip_stdout_flush = 1;
else
skip_stdout_flush = 0;
}
if (skip_stdout_flush && !ferror(f))
return;
}
if (fflush(f)) {
if (errno == EPIPE)
exit(0);
die("write failure on %s: %s", desc, strerror(errno));
}
}
int read_in_full(int fd, void *buf, size_t count)
{
char *p = buf;