--- /dev/null
+* whitespace=!indent,trail,space
+*.[ch] whitespace
--- /dev/null
+*.txt whitespace
ASCIIDOC=asciidoc
ASCIIDOC_EXTRA =
+MANPAGE_XSL = callouts.xsl
INSTALL?=install
RM ?= rm -f
DOC_REF = origin/man
endif
ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a docbook-xsl-172
+MANPAGE_XSL = manpage-1.72.xsl
endif
#
%.1 %.5 %.7 : %.xml
$(RM) $@
- xmlto -m callouts.xsl man $<
+ xmlto -m $(MANPAGE_XSL) man $<
%.xml : %.txt
$(RM) $@+ $@
* The default shell on some FreeBSD did not execute the
argument parsing code correctly and made git unusable.
- * git-svn incorrectly spawned pager even when the user user
+ * git-svn incorrectly spawned pager even when the user
explicitly asked not to.
* sample post-receive hook overquoted the envelope sender
* As git-commit and git-status have been rewritten, "git runstatus"
helper script lost all its users and has been removed.
- * Curl library older than 7.10 is not supported by "git http-push",
- as it does not work without CURLM.
+
+Temporarily disabled
+--------------------
+
+ * "git http-push" is known not to work well with cURL library older
+ than 7.16, and we had reports of repository corruption. It is
+ disabled on such platforms for now. Unfortunately, 1.5.3.8 shares
+ the same issue. In other words, this does not mean you will be
+ fine if you stick to an older git release. For now, please do not
+ use http-push from older git with cURL older than 7.16 if you
+ value your data. A proper fix will hopefully materialize in
+ later versions.
Deprecation notices
-------------------
- * The next feature release of git (this change is scheduled for v1.6.0)
- will by default install dashed form of commands (e.g. "git-commit")
- outside of users' normal $PATH, and will install only selected
- commands ("git" itself, and "gitk") in $PATH. This implies:
+ * From v1.6.0, git will by default install dashed form of commands
+ (e.g. "git-commit") outside of users' normal $PATH, and will install
+ only selected commands ("git" itself, and "gitk") in $PATH. This
+ implies:
- Using dashed forms of git commands (e.g. "git-commit") from the
command line has been informally deprecated since early 2006, but
now it officially is, and will be removed in the future. Use
- dashless forms (e.g. "git commit") instead.
+ dash-less forms (e.g. "git commit") instead.
- Using dashed forms from your scripts, without first prepending the
return value from "git --exec-path" to the scripts' PATH, has been
- Use of dashed forms with "PATH=$(git --exec-path):$PATH; export
PATH" early in your script is not deprecated with this change.
- Users are strongly encouraged to adjust their habits and scripts now
- to prepare for this.
+ Users are strongly encouraged to adjust their habits and scripts now
+ to prepare for this change.
* The post-receive hook was introduced in March 2007 to supersede
the post-update hook, primarily to overcome the command line length
* Comes with much improved gitk, with i18n.
- * Comes with "git gui" 0.9.1 with i18n.
+ * Comes with git-gui 0.9.2 with i18n.
* gitk is now merged as a subdirectory of git.git project, in
preparation for its i18n.
command line in the generated log message, when told to cherry-pick a
commit by naming a tag that points at it. It does not anymore.
- * "git for-each-ref" learned %(xxxdate:<dateformat>) syntax to show the
+ * "git for-each-ref" learned %(xxxdate:<date-format>) syntax to show the
various date fields in different formats.
* "git gc --auto" is a low-impact way to automatically run a variant of
* "git pull --rebase" is a different way to integrate what you fetched
into your current branch.
- * "git fast-export" produces datastream that can be fed to fast-import
+ * "git fast-export" produces data-stream that can be fed to fast-import
to reproduce the history recorded in a git repository.
* "git add -i" takes pathspecs to limit the set of files to work on.
from its first parent.
* "git commit" used to unconditionally strip comment lines that
- began with '#' and removed excess blank lines. This
- behaviour has been made configurable.
+ began with '#' and removed excess blank lines. This behavior has
+ been made configurable.
* "git commit" has been rewritten in C.
* "git status" from a subdirectory now shows relative paths, which
makes copy-and-pasting for git-checkout/git-add/git-rm easier. The
- traditional behaviour to show the full path relative to the top of
+ traditional behavior to show the full path relative to the top of
the work tree can be had by setting status.relativepaths
configuration variable to false.
* "git help" learned "-w" option to show documentation in browsers.
- * In addition there are quite a few internal clean-ups. Notably
+ * In addition there are quite a few internal clean-ups. Notably:
- many fork/exec have been replaced with run-command API,
brought from the msysgit effort.
- enhancement and more use of the strbuf API.
+ * Makefile tweaks to support HP-UX is in.
Fixes since v1.5.3
------------------
* The way "git diff --check" behaves is much more consistent with the way
"git apply --whitespace=warn" works.
- * "git svn" talking with the SVN over http will correctly quote branch
+ * "git svn" talking with the SVN over HTTP will correctly quote branch
and project names.
* "git config" did not work correctly on platforms that define
documentation; a workaround has been implemented.
* "git diff --color-words" colored context lines in a wrong color.
-
---
-exec >/var/tmp/1
-O=v1.5.4-rc4
-echo O=`git describe refs/heads/master`
-git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
When <rev> is not specified, the command annotates the
changes starting backwards from the working tree copy.
This flag makes the command pretend as if the working
- tree copy has the contents of he named file (specify
+ tree copy has the contents of the named file (specify
`-` to make the command read from the standard input).
-M|<num>|::
so that linkgit:git-pull[1] will appropriately merge from that
remote branch. Note that even if this option is not set,
this behavior can be chosen per-branch using the `--track`
- and `--no-track` options. This option defaults to false.
+ and `--no-track` options. This option defaults to true.
branch.<name>.remote::
When in branch <name>, it tells `git fetch` which remote to fetch.
it unless you understand the implications (see linkgit:git-rebase[1]
for details).
+browser.<tool>.path::
+ Override the path for the given tool that may be used to
+ browse HTML help (see '-w' option in linkgit:git-help[1]) or a
+ working repository in gitweb (see linkgit:git-instaweb[1]).
+
clean.requireForce::
A boolean to make git-clean do nothing unless given -f
or -n. Defaults to true.
whenever the corresponding pack is larger than 2 GB. Otherwise
the default is 1.
+pack.packSizeLimit:
+ The default maximum size of a pack. This setting only affects
+ packing to a file, i.e. the git:// protocol is unaffected. It
+ can be overridden by the `\--max-pack-size` option of
+ linkgit:git-repack[1].
+
pull.octopus::
The default merge strategy to use when pulling multiple branches
at once.
fetches is a descendant of `<lbranch>`. This option
overrides that check.
+ifdef::git-pull[]
+\--no-tags::
+endif::git-pull[]
+ifndef::git-pull[]
-n, \--no-tags::
- By default, `git-fetch` fetches tags that point at
- objects that are downloaded from the remote repository
- and stores them locally. This option disables this
- automatic tag following.
+endif::git-pull[]
+ By default, tags that point at objects that are downloaded
+ from the remote repository are fetched and stored locally.
+ This option disables this automatic tag following.
-t, \--tags::
Most of the tags are fetched automatically as branch
working tree to it; use "git checkout <newbranch>" to switch to the
new branch.
-When a local branch is started off a remote branch, git can setup the
+When a local branch is started off a remote branch, git sets up the
branch so that linkgit:git-pull[1] will appropriately merge from that
-remote branch. If this behavior is desired, it is possible to make it
-the default using the global `branch.autosetupmerge` configuration
-flag. Otherwise, it can be chosen per-branch using the `--track`
+remote branch. If this behavior is not desired, it is possible to
+disable it using the global `branch.autosetupmerge` configuration
+flag. That setting can be overridden by using the `--track`
and `--no-track` options.
With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
Set up configuration so that git-pull will automatically
retrieve data from the remote branch. Use this if you always
pull from the same remote branch into the new branch, or if you
- don't want to use "git pull <repository> <refspec>" explicitly. Set the
- branch.autosetupmerge configuration variable to true if you
+ don't want to use "git pull <repository> <refspec>" explicitly.
+ This behavior is the default. Set the
+ branch.autosetupmerge configuration variable to false if you
want git-checkout and git-branch to always behave as if
- '--track' were given.
+ '--no-track' were given.
--no-track::
When a branch is created off a remote branch,
set up configuration so that git-pull will automatically
retrieve data from the remote branch. Use this if you always
pull from the same remote branch into the new branch, or if you
- don't want to use "git pull <repository> <refspec>" explicitly. Set the
- branch.autosetupmerge configuration variable to true if you
+ don't want to use "git pull <repository> <refspec>" explicitly.
+ This behavior is the default. Set the
+ branch.autosetupmerge configuration variable to false if you
want git-checkout and git-branch to always behave as if
- '--track' were given.
+ '--no-track' were given.
--no-track::
When -b is given and a branch is created off a remote branch,
.git/objects/info/alternates to share the objects
with the source repository. The resulting repository
starts out without any object of its own.
+ *NOTE*: this is a possibly dangerous operation; do *not* use
+ it unless you understand what it does. If you clone your
+ repository using this option, then delete branches in the
+ source repository and then run linkgit:git-gc[1] using the
+ '--prune' option in the source repository, it may remove
+ objects which are referenced by the cloned repository.
+
+
--reference <repository>::
If the reference repository is on the local machine
-z, --null::
For all options that output values and/or keys, always
- end values with with the null character (instead of a
+ end values with the null character (instead of a
newline). Use newline instead as a delimiter between
key and value. This allows for secure parsing of the
output without getting confused e.g. by values that
That means that even if you offer only read access (e.g. by using
the pserver method), git-cvsserver should have write access to
the database to work reliably (otherwise you need to make sure
-that the database if up-to-date all the time git-cvsserver is run).
+that the database is up-to-date any time git-cvsserver is executed).
By default it uses SQLite databases in the git directory, named
`gitcvs.<module_name>.sqlite`. Note that the SQLite backend creates
gitcvs.dbname::
Database name. The exact meaning depends on the
- used database driver, for SQLite this is a filename.
+ selected database driver, for SQLite this is a filename.
Supports variable substitution (see below). May
not contain semicolons (`;`).
Default: '%Ggitcvs.%m.sqlite'
with 'DBD::SQLite', reported to work with
'DBD::Pg', and reported *not* to work with 'DBD::mysql'.
Please regard this as an experimental feature. May not
- contain double colons (`:`).
+ contain colons (`:`).
Default: 'SQLite'
gitcvs.dbuser::
being employed to standard error. The tag name will still
be printed to standard out.
+--match <pattern>::
+ Only consider tags matching the given pattern (can be used to avoid
+ leaking private tags made from the repository).
+
EXAMPLES
--------
+
Note that the script tries, as much as possible, to display the HTML
page in a new tab on an already opened browser.
++
+The following browsers are currently supported by 'git-help--browse':
++
+* firefox (this is the default under X Window when not using KDE)
+* iceweasel
+* konqueror (this is the default under KDE)
+* w3m (this is the default outside X Window)
+* links
+* lynx
+* dillo
CONFIGURATION VARIABLES
-----------------------
Sends missing objects to remote repository, and updates the
remote branch.
+*NOTE*: This command is temporarily disabled if your cURL
+library is older than 7.16, as the combination has been reported
+not to work and sometimes corrupts repository.
OPTIONS
-------
--max-pack-size=<n>::
Maximum size of each output packfile, expressed in MiB.
If specified, multiple packfiles may be created.
- The default is unlimited.
+ The default is unlimited, unless the config variable
+ `pack.packSizeLimit` is set.
--incremental::
This flag causes an object already in a pack ignored
-------
include::merge-options.txt[]
+:git-pull: 1
include::fetch-options.txt[]
include::pull-fetch-param.txt[]
include::merge-strategies.txt[]
\--rebase::
- Instead of a merge, perform a rebase after fetching.
- *NOTE:* This is a potentially _dangerous_ mode of operation.
- It rewrites history, which does not bode well when you
- published that history already. Do *not* use this option
- unless you have read linkgit:git-rebase[1] carefully.
+ Instead of a merge, perform a rebase after fetching. If
+ there is a remote ref for the upstream branch, and this branch
+ was rebased since last fetched, the rebase uses that information
+ to avoid rebasing non-local changes.
++
+*NOTE:* This is a potentially _dangerous_ mode of operation.
+It rewrites history, which does not bode well when you
+published that history already. Do *not* use this option
+unless you have read linkgit:git-rebase[1] carefully.
\--no-rebase::
Override earlier \--rebase.
--------
[verse]
'git-remote'
-'git-remote' add [-t <branch>] [-m <branch>] [-f] [--mirror] <name> <url>
+'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
'git-remote' rm <name>
'git-remote' show <name>
'git-remote' prune <name>
* A colon, optionally followed by a stage number (0 to 3) and a
colon, followed by a path; this names a blob object in the
index at the given path. Missing stage number (and the colon
- that follows it) names an stage 0 entry. During a merge, stage
+ that follows it) names a stage 0 entry. During a merge, stage
1 is the common ancestor, stage 2 is the target branch's version
(typically the current branch), and stage 3 is the version from
the branch being merged.
-Here is an illustration, by Jon Loeliger. Both node B and C are
-a commit parents of commit node A. Parent commits are ordered
+Here is an illustration, by Jon Loeliger. Both commit nodes B
+and C are parents of commit node A. Parent commits are ordered
left-to-right.
G H I J
parents of `r1`. `r1{caret}!` includes commit `r1` but excludes
its all parents.
-Here are a handful examples:
+Here are a handful of examples:
D G H D
D F G H I J D F
Specify the primary recipient of the emails generated.
Generally, this will be the upstream maintainer of the
project involved.
+ Default is the value of the 'sendemail.to' configuration value;
+ if that is unspecified, this will be prompted for.
+
The --to option must be repeated for each user you want on the to list.
--------
[verse]
'git-stash' (list | show [<stash>] | apply [<stash>] | clear)
-'git-stash' [save] [message...]
+'git-stash' [save [<message>]]
DESCRIPTION
-----------
OPTIONS
-------
-save::
+save [<message>]::
Save your local modifications to a new 'stash', and run `git-reset
--hard` to revert them. This is the default action when no
- subcommand is given.
+ subcommand is given. The <message> part is optional and gives
+ the description along with the stashed state.
list::
SYNOPSIS
--------
[verse]
-'git-submodule' [--quiet] [-b branch] add <repository> [<path>]
-'git-submodule' [--quiet] [--cached] [status|init|update] [--] [<path>...]
+'git-submodule' [--quiet] add [-b branch] [--] <repository> [<path>]
+'git-submodule' [--quiet] status [--cached] [--] [<path>...]
+'git-submodule' [--quiet] [init|update] [--] [<path>...]
COMMANDS
+
Any other arguments are passed directly to `git log'
+'blame'::
+ Show what revision and author last modified each line of a file. This is
+ identical to `git blame', but SVN revision numbers are shown instead of git
+ commit hashes.
++
+All arguments are passed directly to `git blame'.
+
--
'find-rev'::
When given an SVN revision number of the form 'rN', returns the
------------------------------------------------------------------------
# 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
+# Clone locally - make sure the refs/remotes/ space matches the server
+ mkdir project
+ cd project
+ git-init
+ git remote add origin server:/pub/project
+ git config --add remote.origin.fetch=+refs/remotes/*:refs/remotes/*
+ git fetch
# Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server)
git-svn init http://svn.foo.org/project
# Pull the latest changes from Subversion
branch of the `git.git` repository.
Documentation for older releases are available here:
+* link:v1.5.4/git.html[documentation for release 1.5.4]
+
+* release notes for
+ link:RelNotes-1.5.4.txt[1.5.4].
+
* link:v1.5.3.8/git.html[documentation for release 1.5.3.8]
* release notes for
--- /dev/null
+<!-- callout.xsl: converts asciidoc callouts to man page format -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:template match="co">
+ <xsl:value-of select="concat('▓fB(',substring-after(@id,'-'),')▓fR')"/>
+</xsl:template>
+<xsl:template match="calloutlist">
+ <xsl:text>⌂sp </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text> </xsl:text>
+</xsl:template>
+<xsl:template match="callout">
+ <xsl:value-of select="concat('▓fB',substring-after(@arearefs,'-'),'. ▓fR')"/>
+ <xsl:apply-templates/>
+ <xsl:text>⌂br </xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
however, the initial computation of all object names in the
index takes more than one second, and the index file is written
out after all that happens. Therefore the timestamp of the
-index file will be more than one seconds later than the the
+index file will be more than one seconds later than the
youngest file in the working tree. This means that in these
cases there actually will not be any racily clean entry in
the resulting index.
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.4-rc3.GIT
+DEF_VER=v1.5.4.GIT
LF='
'
- "perl" and POSIX-compliant shells are needed to use most of
the barebone Porcelainish scripts.
- - "cpio" is used by git-merge for saving and restoring the index,
- and by git-clone when doing a local (possibly hardlinked) clone.
+ - "cpio" is used by git-clone when doing a local (possibly
+ hardlinked) clone.
- Some platform specific issues are dealt with Makefile rules,
but depending on your specific installation, you may not
#
# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
#
+# Define NO_SYS_SELECT_H if you don't have sys/select.h.
+#
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
# Enable it on Windows. By default, symrefs are still used.
#
# for now, build 32-bit version
BASIC_LDFLAGS += -L/usr/lib32
endif
+ifeq ($(uname_S),HP-UX)
+ NO_IPV6=YesPlease
+ NO_SETENV=YesPlease
+ NO_STRCASESTR=YesPlease
+ NO_MEMMEM = YesPlease
+ NO_STRLCPY = YesPlease
+ NO_MKDTEMP = YesPlease
+ NO_UNSETENV = YesPlease
+ NO_HSTRERROR = YesPlease
+ NO_SYS_SELECT_H = YesPlease
+endif
ifneq (,$(findstring arm,$(uname_M)))
ARM_SHA1 = YesPlease
endif
COMPAT_CFLAGS += -DNO_UNSETENV
COMPAT_OBJS += compat/unsetenv.o
endif
+ifdef NO_SYS_SELECT_H
+ BASIC_CFLAGS += -DNO_SYS_SELECT_H
+endif
ifdef NO_MMAP
COMPAT_CFLAGS += -DNO_MMAP
COMPAT_OBJS += compat/mmap.o
git-imap-send$X: imap-send.o $(LIB_FILE)
-http.o http-walker.o http-push.o: http.h
+http.o http-walker.o http-push.o transport.o: http.h
git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
static int git_tar_config(const char *var, const char *value)
{
if (!strcmp(var, "tar.umask")) {
- if (!strcmp(value, "user")) {
+ if (value && !strcmp(value, "user")) {
tar_umask = umask(0);
umask(tar_umask);
} else {
{
fprintf(stderr, "%s: %s\n", what, elem->origin ? elem->origin : "()");
}
-static void debug_set(const char *what, const char *match, struct git_attr *attr, void *v)
+static void debug_set(const char *what, const char *match, struct git_attr *attr, const void *v)
{
const char *value = v;
if (*pattern == '/')
pattern++;
if (pathlen < baselen ||
- (baselen && pathname[baselen - 1] != '/') ||
+ (baselen && pathname[baselen] != '/') ||
strncmp(pathname, base, baselen))
return 0;
- return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
+ return fnmatch(pattern, pathname + baselen + 1, FNM_PATHNAME) == 0;
}
static int fill_one(const char *what, struct match_attr *a, int rem)
static int git_apply_config(const char *var, const char *value)
{
if (!strcmp(var, "apply.whitespace")) {
+ if (!value)
+ return config_error_nonbool(var);
apply_default_whitespace = xstrdup(value);
return 0;
}
}
if (!prefixcmp(var, "color.branch.")) {
int slot = parse_branch_color_slot(var, 13);
+ if (!value)
+ return config_error_nonbool(var);
color_parse(value, var, branch_colors[slot]);
return 0;
}
- if (!strcmp(var, "branch.autosetupmerge"))
- branch_track = git_config_bool(var, value);
-
+ if (!strcmp(var, "branch.autosetupmerge")) {
+ branch_track = git_config_bool(var, value);
+ return 0;
+ }
return git_default_config(var, value);
}
}
}
-static void commit_index_files(void)
+static int commit_index_files(void)
{
+ int err = 0;
+
switch (commit_style) {
case COMMIT_AS_IS:
break; /* nothing to do */
case COMMIT_NORMAL:
- commit_lock_file(&index_lock);
+ err = commit_lock_file(&index_lock);
break;
case COMMIT_PARTIAL:
- commit_lock_file(&index_lock);
+ err = commit_lock_file(&index_lock);
rollback_lock_file(&false_lock);
break;
}
+
+ return err;
}
/*
if (get_sha1(use_message, sha1))
die("could not lookup commit %s", use_message);
- commit = lookup_commit(sha1);
+ commit = lookup_commit_reference(sha1);
if (!commit || parse_commit(commit))
die("could not parse commit %s", use_message);
int git_commit_config(const char *k, const char *v)
{
if (!strcmp(k, "commit.template")) {
+ if (!v)
+ return config_error_nonbool(v);
template_file = xstrdup(v);
return 0;
}
unlink(git_path("MERGE_HEAD"));
unlink(git_path("MERGE_MSG"));
+ unlink(git_path("SQUASH_MSG"));
- commit_index_files();
+ if (commit_index_files())
+ die ("Repository has been updated, but unable to write\n"
+ "new_index file. Check that disk is not full or quota is\n"
+ "not exceeded, and then \"git reset HEAD\" to recover.");
rerere();
run_hook(get_index_file(), "post-commit", NULL);
static int git_get_color_config(const char *var, const char *value)
{
if (!strcmp(var, get_color_slot)) {
+ if (!value)
+ config_error_nonbool(var);
color_parse(value, var, parsed_color);
get_color_found = 1;
}
static int tags; /* But allow any tags if --tags is specified */
static int abbrev = DEFAULT_ABBREV;
static int max_candidates = 10;
+const char *pattern = NULL;
struct commit_name {
int prio; /* annotated tag = 2, tag = 1, head = 0 */
* Otherwise only annotated tags are used.
*/
if (!prefixcmp(path, "refs/tags/")) {
- if (object->type == OBJ_TAG)
+ if (object->type == OBJ_TAG) {
prio = 2;
- else
+ if (pattern && fnmatch(pattern, path + 10, 0))
+ prio = 0;
+ } else
prio = 1;
}
else
OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
OPT__ABBREV(&abbrev),
OPT_INTEGER(0, "candidates", &max_candidates,
- "consider <n> most recent tags (default: 10)"),
+ "consider <n> most recent tags (default: 10)"),
+ OPT_STRING(0, "match", &pattern, "pattern",
+ "only consider tags matching <pattern>"),
OPT_END(),
};
save_commit_buffer = 0;
if (contains) {
- const char **args = xmalloc((4 + argc) * sizeof(char*));
+ const char **args = xmalloc((6 + argc) * sizeof(char*));
int i = 0;
args[i++] = "name-rev";
args[i++] = "--name-only";
- if (!all)
+ args[i++] = "--no-undefined";
+ if (!all) {
args[i++] = "--tags";
+ if (pattern) {
+ char *s = xmalloc(strlen("--refs=refs/tags/") + strlen(pattern) + 1);
+ sprintf(s, "--refs=refs/tags/%s", pattern);
+ args[i++] = s;
+ }
+ }
memcpy(args + i, argv, argc * sizeof(char*));
args[i + argc] = NULL;
return cmd_name_rev(i + argc, args, prefix);
fprintf(stderr, "Checking commit %s\n",
sha1_to_hex(commit->object.sha1));
+ if (!commit->date)
+ return objerror(&commit->object, "invalid author/committer line");
+
if (memcmp(buffer, "tree ", 5))
return objerror(&commit->object, "invalid format - expected 'tree' line");
if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
if (!commit->parents && show_root)
printf("root %s\n", sha1_to_hex(commit->object.sha1));
- if (!commit->date)
- printf("bad commit date in %s\n",
- sha1_to_hex(commit->object.sha1));
return 0;
}
static int gc_config(const char *var, const char *value)
{
if (!strcmp(var, "gc.packrefs")) {
- if (!strcmp(value, "notbare"))
+ if (value && !strcmp(value, "notbare"))
pack_refs = -1;
else
pack_refs = git_config_bool(var, value);
*/
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
if (!is_absolute_path(template_dir)) {
- const char *exec_path = git_exec_path();
- template_dir = prefix_path(exec_path, strlen(exec_path),
- template_dir);
+ struct strbuf d = STRBUF_INIT;
+ strbuf_addf(&d, "%s/%s", git_exec_path(), template_dir);
+ template_dir = strbuf_detach(&d, NULL);
}
}
strcpy(template_path, template_dir);
{
if (!strcmp(var, "format.subjectprefix")) {
if (!value)
- die("format.subjectprefix without value");
+ config_error_nonbool(var);
fmt_patch_subject_prefix = xstrdup(value);
return 0;
}
}
if (!strcmp(var, "format.suffix")) {
if (!value)
- die("format.suffix without value");
+ return config_error_nonbool(var);
fmt_patch_suffix = xstrdup(value);
return 0;
}
return 0;
}
if (!strcmp(var, "format.numbered")) {
- if (!strcasecmp(value, "auto")) {
+ if (value && !strcasecmp(value, "auto")) {
auto_number = 1;
return 0;
}
-
numbered = git_config_bool(var, value);
return 0;
}
}
/* returns a static buffer */
-static const char* get_rev_name(struct object *o)
+static const char *get_rev_name(struct object *o)
{
static char buffer[1024];
struct rev_name *n;
struct commit *c;
if (o->type != OBJ_COMMIT)
- return "undefined";
+ return NULL;
c = (struct commit *) o;
n = c->util;
if (!n)
- return "undefined";
+ return NULL;
if (!n->generation)
return n->tip_name;
int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
struct object_array revs = { 0, 0, NULL };
- int all = 0, transform_stdin = 0;
+ int all = 0, transform_stdin = 0, allow_undefined = 1;
struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"),
OPT_GROUP(""),
OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"),
OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"),
+ OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"),
OPT_END(),
};
else if (++forty == 40 &&
!ishex(*(p+1))) {
unsigned char sha1[40];
- const char *name = "undefined";
+ const char *name = NULL;
char c = *(p+1);
forty = 0;
}
*(p+1) = c;
- if (!strcmp(name, "undefined"))
+ if (!name)
continue;
- fwrite(p_start, p - p_start + 1, 1,
- stdout);
+ fwrite(p_start, p - p_start + 1, 1, stdout);
printf(" (%s)", name);
p_start = p + 1;
}
max = get_max_object_index();
for (i = 0; i < max; i++) {
struct object * obj = get_indexed_object(i);
+ const char *name;
if (!obj)
continue;
if (!data.name_only)
printf("%s ", sha1_to_hex(obj->sha1));
- printf("%s\n", get_rev_name(obj));
+ name = get_rev_name(obj);
+ if (name)
+ printf("%s\n", name);
+ else if (allow_undefined)
+ printf("undefined\n");
+ else
+ die("cannot describe '%s'", sha1_to_hex(obj->sha1));
}
} else {
int i;
for (i = 0; i < revs.nr; i++) {
+ const char *name;
if (!data.name_only)
printf("%s ", revs.objects[i].name);
- printf("%s\n", get_rev_name(revs.objects[i].item));
+ name = get_rev_name(revs.objects[i].item);
+ if (name)
+ printf("%s\n", name);
+ else if (allow_undefined)
+ printf("undefined\n");
+ else
+ die("cannot describe '%s'", sha1_to_hex(revs.objects[i].item->sha1));
}
}
static const char *base_name;
static int progress = 1;
static int window = 10;
-static uint32_t pack_size_limit;
+static uint32_t pack_size_limit, pack_size_limit_cfg;
static int depth = 50;
static int delta_search_threads = 1;
static int pack_to_stdout;
return m;
}
-static unsigned long free_unpacked(struct unpacked *n)
+static unsigned long free_unpacked_data(struct unpacked *n)
{
unsigned long freed_mem = sizeof_delta_index(n->index);
free_delta_index(n->index);
free(n->data);
n->data = NULL;
}
+ return freed_mem;
+}
+
+static unsigned long free_unpacked(struct unpacked *n)
+{
+ unsigned long freed_mem = free_unpacked_data(n);
n->entry = NULL;
n->depth = 0;
return freed_mem;
mem_usage > window_memory_limit &&
count > 1) {
uint32_t tail = (idx + window - count) % window;
- mem_usage -= free_unpacked(array + tail);
+ mem_usage -= free_unpacked_data(array + tail);
count--;
}
if (!m->entry)
break;
ret = try_delta(n, m, max_depth, &mem_usage);
+ if (window_memory_limit &&
+ mem_usage > window_memory_limit)
+ mem_usage -= free_unpacked_data(m);
if (ret < 0)
break;
else if (ret > 0)
p[i].data_ready = 0;
/* try to split chunks on "path" boundaries */
- while (sub_size < list_size && list[sub_size]->hash &&
+ while (sub_size && sub_size < list_size &&
+ list[sub_size]->hash &&
list[sub_size]->hash == list[sub_size-1]->hash)
sub_size++;
die("bad pack.indexversion=%d", pack_idx_default_version);
return 0;
}
+ if (!strcmp(k, "pack.packsizelimit")) {
+ pack_size_limit_cfg = git_config_ulong(k, v);
+ return 0;
+ }
return git_default_config(k, v);
}
}
if (!prefixcmp(arg, "--max-pack-size=")) {
char *end;
+ pack_size_limit_cfg = 0;
pack_size_limit = strtoul(arg+16, &end, 0) * 1024 * 1024;
if (!arg[16] || *end)
usage(pack_usage);
if (pack_to_stdout != !base_name)
usage(pack_usage);
+ if (!pack_to_stdout && !pack_size_limit)
+ pack_size_limit = pack_size_limit_cfg;
+
if (pack_to_stdout && pack_size_limit)
die("--max-pack-size cannot be used to build a pack for transfer.");
}
}
+/*
+ * Write errors (particularly out of space) can result in
+ * failed temporary packs (and more rarely indexes and other
+ * files begining with "tmp_") accumulating in the
+ * object directory.
+ */
+static void remove_temporary_files(void)
+{
+ DIR *dir;
+ struct dirent *de;
+ char* dirname=get_object_directory();
+
+ dir = opendir(dirname);
+ if (!dir) {
+ fprintf(stderr, "Unable to open object directory %s\n",
+ dirname);
+ return;
+ }
+ while ((de = readdir(dir)) != NULL) {
+ if (!prefixcmp(de->d_name, "tmp_")) {
+ char name[PATH_MAX];
+ int c = snprintf(name, PATH_MAX, "%s/%s",
+ dirname, de->d_name);
+ if (c < 0 || c >= PATH_MAX)
+ continue;
+ if (expire) {
+ struct stat st;
+ if (stat(name, &st) != 0 || st.st_mtime >= expire)
+ continue;
+ }
+ printf("Removing stale temporary file %s\n", name);
+ if (!show_only)
+ unlink(name);
+ }
+ }
+ closedir(dir);
+}
+
int cmd_prune(int argc, const char **argv, const char *prefix)
{
int i;
sync();
prune_packed_objects(show_only);
+ remove_temporary_files();
return 0;
}
struct cmd_reflog_expire_cb *cmd;
};
+struct collected_reflog {
+ unsigned char sha1[20];
+ char reflog[FLEX_ARRAY];
+};
+struct collect_reflog_cb {
+ struct collected_reflog **e;
+ int alloc;
+ int nr;
+};
+
#define INCOMPLETE (1u<<10)
#define STUDYING (1u<<11)
return status;
}
+static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
+{
+ struct collected_reflog *e;
+ struct collect_reflog_cb *cb = cb_data;
+ size_t namelen = strlen(ref);
+
+ e = xmalloc(sizeof(*e) + namelen + 1);
+ hashcpy(e->sha1, sha1);
+ memcpy(e->reflog, ref, namelen + 1);
+ ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
+ cb->e[cb->nr++] = e;
+ return 0;
+}
+
static int reflog_expire_config(const char *var, const char *value)
{
- if (!strcmp(var, "gc.reflogexpire"))
+ if (!strcmp(var, "gc.reflogexpire")) {
+ if (!value)
+ config_error_nonbool(var);
default_reflog_expire = approxidate(value);
- else if (!strcmp(var, "gc.reflogexpireunreachable"))
+ return 0;
+ }
+ if (!strcmp(var, "gc.reflogexpireunreachable")) {
+ if (!value)
+ config_error_nonbool(var);
default_reflog_expire_unreachable = approxidate(value);
- else
- return git_default_config(var, value);
- return 0;
+ return 0;
+ }
+ return git_default_config(var, value);
}
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
putchar('\n');
}
- if (do_all)
- status |= for_each_reflog(expire_reflog, &cb);
+ if (do_all) {
+ struct collect_reflog_cb collected;
+ int i;
+
+ memset(&collected, 0, sizeof(collected));
+ for_each_reflog(collect_reflog, &collected);
+ for (i = 0; i < collected.nr; i++) {
+ struct collected_reflog *e = collected.e[i];
+ status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
+ free(e);
+ }
+ free(collected.e);
+ }
+
while (i < argc) {
const char *ref = argv[i++];
unsigned char sha1[20];
static int git_show_branch_config(const char *var, const char *value)
{
if (!strcmp(var, "showbranch.default")) {
+ if (!value)
+ return config_error_nonbool(var);
if (default_alloc <= default_num + 1) {
default_alloc = default_alloc * 3 / 2 + 20;
default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
{
if (!strcmp(var, "user.signingkey")) {
if (!value)
- die("user.signingkey without value");
+ return config_error_nonbool(value);
set_signingkey(value);
return 0;
}
extern int git_config_rename_section(const char *, const char *);
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value);
+extern int config_error_nonbool(const char *);
#define MAX_GITNAME (1000)
extern char git_default_email[MAX_GITNAME];
return i - 1;
}
i = strtol(name, &end, 10);
- if (*name && !*end && i >= -1 && i <= 255)
+ if (end - name == len && i >= -1 && i <= 255)
return i;
return -2;
}
}
if (!strcmp(var, "user.name")) {
+ if (!value)
+ return config_error_nonbool(var);
strlcpy(git_default_name, value, sizeof(git_default_name));
return 0;
}
if (!strcmp(var, "user.email")) {
+ if (!value)
+ return config_error_nonbool(var);
strlcpy(git_default_email, value, sizeof(git_default_email));
return 0;
}
if (!strcmp(var, "i18n.commitencoding")) {
+ if (!value)
+ return config_error_nonbool(var);
git_commit_encoding = xstrdup(value);
return 0;
}
if (!strcmp(var, "i18n.logoutputencoding")) {
+ if (!value)
+ return config_error_nonbool(var);
git_log_output_encoding = xstrdup(value);
return 0;
}
}
if (!strcmp(var, "core.pager")) {
+ if (!value)
+ return config_error_nonbool(var);
pager_program = xstrdup(value);
return 0;
}
if (!strcmp(var, "core.editor")) {
+ if (!value)
+ return config_error_nonbool(var);
editor_program = xstrdup(value);
return 0;
}
if (!strcmp(var, "core.excludesfile")) {
if (!value)
- die("core.excludesfile without value");
+ return config_error_nonbool(var);
excludes_file = xstrdup(value);
return 0;
}
if (!strcmp(var, "core.whitespace")) {
+ if (!value)
+ return config_error_nonbool(var);
whitespace_rule_cfg = parse_whitespace_rule(value);
return 0;
}
system_wide = ETC_GITCONFIG;
if (!is_absolute_path(system_wide)) {
/* interpret path relative to exec-dir */
- const char *exec_path = git_exec_path();
- system_wide = prefix_path(exec_path, strlen(exec_path),
- system_wide);
+ struct strbuf d = STRBUF_INIT;
+ strbuf_addf(&d, "%s/%s", git_exec_path(), system_wide);
+ system_wide = strbuf_detach(&d, NULL);
}
}
return system_wide;
size_t equal_offset = size, bracket_offset = size;
ssize_t offset;
+contline:
for (offset = offset_-2; offset > 0
&& contents[offset] != '\n'; offset--)
switch (contents[offset]) {
case '=': equal_offset = offset; break;
case ']': bracket_offset = offset; break;
}
+ if (offset > 0 && contents[offset-1] == '\\') {
+ offset_ = offset;
+ goto contline;
+ }
if (bracket_offset < equal_offset) {
*found_bracket = 1;
offset = bracket_offset+1;
free(config_filename);
return ret;
}
+
+/*
+ * Call this to report error for your variable that should not
+ * get a boolean value (i.e. "[my] var" means "true").
+ */
+int config_error_nonbool(const char *var)
+{
+ return error("Missing value for '%s'", var);
+}
NO_EXPAT=@NO_EXPAT@
NEEDS_LIBICONV=@NEEDS_LIBICONV@
NEEDS_SOCKET=@NEEDS_SOCKET@
+NO_SYS_SELECT_H=@NO_SYS_SELECT_H@
NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@
NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@
## Checks for header files.
AC_MSG_NOTICE([CHECKS for header files])
#
+# Define NO_SYS_SELECT_H if you don't have sys/select.h.
+AC_CHECK_HEADER([sys/select.h],
+[NO_SYS_SELECT_H=],
+[NO_SYS_SELECT_H=UnfortunatelyYes])
+AC_SUBST(NO_SYS_SELECT_H)
+#
# Define OLD_ICONV if your library has an old iconv(), where the second
# (input buffer pointer) parameter is declared with type (const char **).
AC_DEFUN([OLDICONVTEST_SRC], [[
if (git_proxy_command)
return 0;
+ if (!value)
+ return config_error_nonbool(var);
/* [core]
* ;# matches www.kernel.org as well
* gitproxy = netcatter-1 for kernel.org
__git_ps1 ()
{
- local b="$(git symbolic-ref HEAD 2>/dev/null)"
- if [ -n "$b" ]; then
+ local g="$(git rev-parse --git-dir 2>/dev/null)"
+ if [ -n "$g" ]; then
+ local r
+ local b
+ if [ -d "$g/../.dotest" ]
+ then
+ r="|AM/REBASE"
+ b="$(git symbolic-ref HEAD 2>/dev/null)"
+ elif [ -f "$g/.dotest-merge/interactive" ]
+ then
+ r="|REBASE-i"
+ b="$(cat $g/.dotest-merge/head-name)"
+ elif [ -d "$g/.dotest-merge" ]
+ then
+ r="|REBASE-m"
+ b="$(cat $g/.dotest-merge/head-name)"
+ elif [ -f "$g/MERGE_HEAD" ]
+ then
+ r="|MERGING"
+ b="$(git symbolic-ref HEAD 2>/dev/null)"
+ else
+ if [ -f $g/BISECT_LOG ]
+ then
+ r="|BISECTING"
+ fi
+ if ! b="$(git symbolic-ref HEAD 2>/dev/null)"
+ then
+ b="$(cut -c1-7 $g/HEAD)..."
+ fi
+ fi
+
if [ -n "$1" ]; then
- printf "$1" "${b##refs/heads/}"
+ printf "$1" "${b##refs/heads/}$r"
else
- printf " (%s)" "${b##refs/heads/}"
+ printf " (%s)" "${b##refs/heads/}$r"
fi
fi
}
(setq ,l (remove e ,l))
e))
+(defvar git-blame-log-oneline-format
+ "format:[%cr] %cn: %s"
+ "*Formatting option used for describing current line in the minibuffer.
+
+This option is used to pass to git log --pretty= command-line option,
+and describe which commit the current line was made.")
+
(defvar git-blame-dark-colors
(git-blame-color-scale "0c" "04" "24" "1c" "2c" "34" "14" "3c")
"*List of colors (format #RGB) to use in a dark environment.
(defun git-describe-commit (hash)
(with-temp-buffer
(call-process "git" nil t nil
- "log" "-1" "--pretty=oneline"
+ "log" "-1"
+ (concat "--pretty=" git-blame-log-oneline-format)
hash)
(buffer-substring (point-min) (1- (point-max)))))
;;
;; TODO
;; - portability to XEmacs
-;; - better handling of subprocess errors
;; - diff against other branch
;; - renaming files from the status buffer
;; - creating tags
(append (git-get-env-strings env) (list "git") args))
(apply #'call-process "git" nil buffer nil args)))
+(defun git-call-process-display-error (&rest args)
+ "Wrapper for call-process that displays error messages."
+ (let* ((dir default-directory)
+ (buffer (get-buffer-create "*Git Command Output*"))
+ (ok (with-current-buffer buffer
+ (let ((default-directory dir)
+ (buffer-read-only nil))
+ (erase-buffer)
+ (eq 0 (apply 'call-process "git" nil (list buffer t) nil args))))))
+ (unless ok (display-message-or-buffer buffer))
+ ok))
+
(defun git-call-process-env-string (env &rest args)
"Wrapper for call-process that sets environment strings,
and returns the process output as a string."
(when reason
(push reason args)
(push "-m" args))
- (eq 0 (apply #'git-call-process-env nil nil "update-ref" args))))
+ (apply 'git-call-process-display-error "update-ref" args)))
(defun git-read-tree (tree &optional index-file)
"Read a tree into the index file."
(?\100 " (type change file -> subproject)")
(?\120 " (type change symlink -> subproject)")
(t " (subproject)")))
+ (?\110 nil) ;; directory (internal, not a real git state)
(?\000 ;; deleted or unknown
(case old-type
(?\120 " (symlink)")
(?\160 " (subproject)")))
(t (format " (unknown type %o)" new-type)))))
- (if str (propertize str 'face 'git-status-face) "")))
+ (cond (str (propertize str 'face 'git-status-face))
+ ((eq new-type ?\110) "/")
+ (t ""))))
(defun git-rename-as-string (info)
"Return a string describing the copy or rename associated with INFO, or an empty string if none."
(with-temp-buffer
(apply #'git-call-process-env t nil "ls-files" "-z" (append options (list "--") files))
(goto-char (point-min))
- (while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
+ (while (re-search-forward "\\([^\0]*?\\)\\(/?\\)\0" nil t 1)
(let ((name (match-string 1)))
- (push (git-create-fileinfo default-state name) infolist)
+ (push (git-create-fileinfo default-state name 0
+ (if (string-equal "/" (match-string 2)) (lsh ?\110 9) 0))
+ infolist)
(setq files (delete name files)))))
(git-insert-info-list status infolist)
files))
(defun git-run-ls-files-with-excludes (status files default-state &rest options)
"Run git-ls-files on FILES with appropriate --exclude-from options."
(let ((exclude-files (git-get-exclude-files)))
- (apply #'git-run-ls-files status files default-state
+ (apply #'git-run-ls-files status files default-state "--directory"
(concat "--exclude-per-directory=" git-per-dir-ignore-file)
(append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
(git-refresh-files)
(git-refresh-ewoc-hf git-status)))
+(defun git-mark-files (status files)
+ "Mark all the specified FILES, and unmark the others."
+ (setq files (sort files #'string-lessp))
+ (let ((file (and files (pop files)))
+ (node (ewoc-nth status 0)))
+ (while node
+ (let ((info (ewoc-data node)))
+ (if (and file (string-equal (git-fileinfo->name info) file))
+ (progn
+ (unless (git-fileinfo->marked info)
+ (setf (git-fileinfo->marked info) t)
+ (setf (git-fileinfo->needs-refresh info) t))
+ (setq file (pop files))
+ (setq node (ewoc-next status node)))
+ (when (git-fileinfo->marked info)
+ (setf (git-fileinfo->marked info) nil)
+ (setf (git-fileinfo->needs-refresh info) t))
+ (if (and file (string-lessp file (git-fileinfo->name info)))
+ (setq file (pop files))
+ (setq node (ewoc-next status node))))))))
+
(defun git-marked-files ()
"Return a list of all marked files, or if none a list containing just the file at cursor position."
(unless git-status (error "Not in git-status buffer."))
(if (or (not (string-equal tree head-tree))
(yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? "))
(let ((commit (git-commit-tree buffer tree head)))
- (condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
- (condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
- (with-current-buffer buffer (erase-buffer))
- (git-update-status-files (git-get-filenames files) 'uptodate)
- (git-call-process-env nil nil "rerere")
- (git-call-process-env nil nil "gc" "--auto")
- (git-refresh-files)
- (git-refresh-ewoc-hf git-status)
- (message "Committed %s." commit)
- (git-run-hook "post-commit" nil))
+ (when commit
+ (condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
+ (condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
+ (with-current-buffer buffer (erase-buffer))
+ (git-update-status-files (git-get-filenames files) 'uptodate)
+ (git-call-process-env nil nil "rerere")
+ (git-call-process-env nil nil "gc" "--auto")
+ (git-refresh-files)
+ (git-refresh-ewoc-hf git-status)
+ (message "Committed %s." commit)
+ (git-run-hook "post-commit" nil)))
(message "Commit aborted."))))
(message "No files to commit.")))
(delete-file index-file))))))
"Add marked file(s) to the index cache."
(interactive)
(let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
+ ;; FIXME: add support for directories
(unless files
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
- (apply #'git-call-process-env nil nil "update-index" "--add" "--" files)
- (git-update-status-files files 'uptodate)
- (git-success-message "Added" files)))
+ (when (apply 'git-call-process-display-error "update-index" "--add" "--" files)
+ (git-update-status-files files 'uptodate)
+ (git-success-message "Added" files))))
(defun git-ignore-file ()
"Add marked file(s) to the ignore list."
(format "Remove %d file%s? " (length files) (if (> (length files) 1) "s" "")))
(progn
(dolist (name files)
- (when (file-exists-p name) (delete-file name)))
- (apply #'git-call-process-env nil nil "update-index" "--remove" "--" files)
- (git-update-status-files files nil)
- (git-success-message "Removed" files))
+ (ignore-errors
+ (if (file-directory-p name)
+ (delete-directory name)
+ (delete-file name))))
+ (when (apply 'git-call-process-display-error "update-index" "--remove" "--" files)
+ (git-update-status-files files nil)
+ (git-success-message "Removed" files)))
(message "Aborting"))))
(defun git-revert-file ()
"Revert changes to the marked file(s)."
(interactive)
- (let ((files (git-marked-files))
+ (let ((files (git-marked-files-state 'added 'deleted 'modified 'unmerged))
added modified)
(when (and files
(yes-or-no-p
('deleted (push (git-fileinfo->name info) modified))
('unmerged (push (git-fileinfo->name info) modified))
('modified (push (git-fileinfo->name info) modified))))
- (when added
- (apply #'git-call-process-env nil nil "update-index" "--force-remove" "--" added))
- (when modified
- (apply #'git-call-process-env nil nil "checkout" "HEAD" modified))
- (git-update-status-files (append added modified) 'uptodate)
- (git-success-message "Reverted" (git-get-filenames files)))))
+ ;; check if a buffer contains one of the files and isn't saved
+ (dolist (file modified)
+ (let ((buffer (get-file-buffer file)))
+ (when (and buffer (buffer-modified-p buffer))
+ (error "Buffer %s is modified. Please kill or save modified buffers before reverting." (buffer-name buffer)))))
+ (let ((ok (and
+ (or (not added)
+ (apply 'git-call-process-display-error "update-index" "--force-remove" "--" added))
+ (or (not modified)
+ (apply 'git-call-process-display-error "checkout" "HEAD" modified)))))
+ (git-update-status-files (append added modified) 'uptodate)
+ (when ok
+ (dolist (file modified)
+ (let ((buffer (get-file-buffer file)))
+ (when buffer (with-current-buffer buffer (revert-buffer t t t)))))
+ (git-success-message "Reverted" (git-get-filenames files)))))))
(defun git-resolve-file ()
"Resolve conflicts in marked file(s)."
(interactive)
(let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
(when files
- (apply #'git-call-process-env nil nil "update-index" "--" files)
- (git-update-status-files files 'uptodate)
- (git-success-message "Resolved" files))))
+ (when (apply 'git-call-process-display-error "update-index" "--" files)
+ (git-update-status-files files 'uptodate)
+ (git-success-message "Resolved" files)))))
(defun git-remove-handled ()
"Remove handled files from the status list."
(message "Inserting unknown files...done"))
(git-remove-handled)))
+(defun git-expand-directory (info)
+ "Expand the directory represented by INFO to list its files."
+ (when (eq (lsh (git-fileinfo->new-perm info) -9) ?\110)
+ (let ((dir (git-fileinfo->name info)))
+ (git-set-filenames-state git-status (list dir) nil)
+ (git-run-ls-files-with-excludes git-status (list (concat dir "/")) 'unknown "-o")
+ (git-refresh-files)
+ (git-refresh-ewoc-hf git-status)
+ t)))
+
(defun git-setup-diff-buffer (buffer)
"Setup a buffer for displaying a diff."
(let ((dir default-directory))
(goto-char (point-min))
(when (re-search-forward "\n+\\'" nil t)
(replace-match "\n" t t))
- (when sign-off (git-append-sign-off committer-name committer-email)))))
+ (when sign-off (git-append-sign-off committer-name committer-email)))
+ buffer))
(defun git-commit-file ()
"Commit the marked file(s), asking for a commit message."
(setq buffer-file-coding-system coding-system)
(re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t))))
+(defun git-setup-commit-buffer (commit)
+ "Setup the commit buffer with the contents of COMMIT."
+ (let (author-name author-email subject date msg)
+ (with-temp-buffer
+ (let ((coding-system (git-get-logoutput-coding-system)))
+ (git-call-process-env t nil "log" "-1" commit)
+ (goto-char (point-min))
+ (when (re-search-forward "^Author: *\\(.*\\) <\\(.*\\)>$" nil t)
+ (setq author-name (match-string 1))
+ (setq author-email (match-string 2)))
+ (when (re-search-forward "^Date: *\\(.*\\)$" nil t)
+ (setq date (match-string 1)))
+ (while (re-search-forward "^ \\(.*\\)$" nil t)
+ (push (match-string 1) msg))
+ (setq msg (nreverse msg))
+ (setq subject (pop msg))
+ (while (and msg (zerop (length (car msg))) (pop msg)))))
+ (git-setup-log-buffer (get-buffer-create "*git-commit*")
+ author-name author-email subject date
+ (mapconcat #'identity msg "\n"))))
+
+(defun git-get-commit-files (commit)
+ "Retrieve the list of files modified by COMMIT."
+ (let (files)
+ (with-temp-buffer
+ (git-call-process-env t nil "diff-tree" "-r" "-z" "--name-only" "--no-commit-id" commit)
+ (goto-char (point-min))
+ (while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
+ (push (match-string 1) files)))
+ files))
+
+(defun git-amend-commit ()
+ "Undo the last commit on HEAD, and set things up to commit an
+amended version of it."
+ (interactive)
+ (unless git-status (error "Not in git-status buffer."))
+ (when (git-empty-db-p) (error "No commit to amend."))
+ (let* ((commit (git-rev-parse "HEAD"))
+ (files (git-get-commit-files commit)))
+ (when (git-call-process-display-error "reset" "--soft" "HEAD^")
+ (git-update-status-files (copy-sequence files) 'uptodate)
+ (git-mark-files git-status files)
+ (git-refresh-files)
+ (git-setup-commit-buffer commit)
+ (git-commit-file))))
+
(defun git-find-file ()
"Visit the current file in its own buffer."
(interactive)
(unless git-status (error "Not in git-status buffer."))
(let ((info (ewoc-data (ewoc-locate git-status))))
- (find-file (git-fileinfo->name info))
- (when (eq 'unmerged (git-fileinfo->state info))
- (smerge-mode 1))))
+ (unless (git-expand-directory info)
+ (find-file (git-fileinfo->name info))
+ (when (eq 'unmerged (git-fileinfo->state info))
+ (smerge-mode 1)))))
(defun git-find-file-other-window ()
"Visit the current file in its own buffer in another window."
(unless git-status-mode-map
(let ((map (make-keymap))
+ (commit-map (make-sparse-keymap))
(diff-map (make-sparse-keymap))
(toggle-map (make-sparse-keymap)))
(suppress-keymap map)
(define-key map " " 'git-next-file)
(define-key map "a" 'git-add-file)
(define-key map "c" 'git-commit-file)
+ (define-key map "\C-c" commit-map)
(define-key map "d" diff-map)
(define-key map "=" 'git-diff-file)
(define-key map "f" 'git-find-file)
(define-key map "x" 'git-remove-handled)
(define-key map "\C-?" 'git-unmark-file-up)
(define-key map "\M-\C-?" 'git-unmark-all)
+ ; the commit submap
+ (define-key commit-map "\C-a" 'git-amend-commit)
; the diff submap
(define-key diff-map "b" 'git-diff-file-base)
(define-key diff-map "c" 'git-diff-file-combined)
optparse.make_option("--origin", dest="origin"),
optparse.make_option("--reset", action="store_true", dest="reset"),
optparse.make_option("--log-substitutions", dest="substFile"),
- optparse.make_option("--dry-run", action="store_true"),
optparse.make_option("--direct", dest="directSubmit", action="store_true"),
- optparse.make_option("--trust-me-like-a-fool", dest="trustMeLikeAFool", action="store_true"),
optparse.make_option("-M", dest="detectRename", action="store_true"),
]
self.description = "Submit changes from git to the perforce depot."
self.firstTime = True
self.reset = False
self.interactive = True
- self.dryRun = False
self.substFile = ""
self.firstTime = True
self.origin = ""
self.directSubmit = False
- self.trustMeLikeAFool = False
self.detectRename = False
self.verbose = False
self.isWindows = (platform.system() == "Windows")
separatorLine += "\r"
separatorLine += "\n"
- response = "e"
- if self.trustMeLikeAFool:
- response = "y"
-
- firstIteration = True
- while response == "e":
- if not firstIteration:
- response = raw_input("Do you want to submit this change? [y]es/[e]dit/[n]o/[s]kip ")
- firstIteration = False
- if response == "e":
- [handle, fileName] = tempfile.mkstemp()
- tmpFile = os.fdopen(handle, "w+")
- tmpFile.write(submitTemplate + separatorLine + diff)
- tmpFile.close()
- defaultEditor = "vi"
- if platform.system() == "Windows":
- defaultEditor = "notepad"
- editor = os.environ.get("EDITOR", defaultEditor);
- system(editor + " " + fileName)
- tmpFile = open(fileName, "rb")
- message = tmpFile.read()
- tmpFile.close()
- os.remove(fileName)
- submitTemplate = message[:message.index(separatorLine)]
- if self.isWindows:
- submitTemplate = submitTemplate.replace("\r\n", "\n")
-
- if response == "y" or response == "yes":
- if self.dryRun:
- print submitTemplate
- raw_input("Press return to continue...")
- else:
- if self.directSubmit:
- print "Submitting to git first"
- os.chdir(self.oldWorkingDirectory)
- write_pipe("git commit -a -F -", submitTemplate)
- os.chdir(self.clientPath)
-
- write_pipe("p4 submit -i", submitTemplate)
- elif response == "s":
- for f in editedFiles:
- system("p4 revert \"%s\"" % f);
- for f in filesToAdd:
- system("p4 revert \"%s\"" % f);
- system("rm %s" %f)
- for f in filesToDelete:
- system("p4 delete \"%s\"" % f);
- return
- else:
- print "Not submitting!"
- self.interactive = False
+ [handle, fileName] = tempfile.mkstemp()
+ tmpFile = os.fdopen(handle, "w+")
+ tmpFile.write(submitTemplate + separatorLine + diff)
+ tmpFile.close()
+ defaultEditor = "vi"
+ if platform.system() == "Windows":
+ defaultEditor = "notepad"
+ editor = os.environ.get("EDITOR", defaultEditor);
+ system(editor + " " + fileName)
+ tmpFile = open(fileName, "rb")
+ message = tmpFile.read()
+ tmpFile.close()
+ os.remove(fileName)
+ submitTemplate = message[:message.index(separatorLine)]
+ if self.isWindows:
+ submitTemplate = submitTemplate.replace("\r\n", "\n")
+
+ if self.directSubmit:
+ print "Submitting to git first"
+ os.chdir(self.oldWorkingDirectory)
+ write_pipe("git commit -a -F -", submitTemplate)
+ os.chdir(self.clientPath)
+
+ write_pipe("p4 submit -i", submitTemplate)
else:
fileName = "submit.txt"
file = open(fileName, "w+")
sync = P4Sync()
sync.run([])
- response = raw_input("Do you want to rebase current HEAD from Perforce now using git-p4 rebase? [y]es/[n]o ")
- if response == "y" or response == "yes":
- rebase = P4Rebase()
- rebase.rebase()
+ rebase = P4Rebase()
+ rebase.rebase()
os.remove(self.configFile)
return True
stat = filedata[j]
j += 1
text = ''
- while j < len(filedata) and filedata[j]['code'] in ('text',
- 'binary'):
- text += filedata[j]['data']
+ while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
+ tmp = filedata[j]['data']
+ if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
+ tmp = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', tmp)
+ elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
+ tmp = re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', tmp)
+ text += tmp
j += 1
return self.rebase()
def rebase(self):
+ if os.system("git update-index --refresh") != 0:
+ die("Some files in your working directory are modified and different than what is in your index. You can use git update-index <filename> to bring the index up-to-date or stash away all your changes with git stash.");
+ if len(read_pipe("git diff-index HEAD --")) > 0:
+ die("You have uncommited changes. Please commit them before rebasing or stash them away with git stash.");
+
[upstream, settings] = findUpstreamBranchPoint()
if len(upstream) == 0:
die("Cannot find upstream branchpoint for rebase")
depotPath = args[0]
depotDir = re.sub("(@[^@]*)$", "", depotPath)
depotDir = re.sub("(#[^#]*)$", "", depotDir)
- depotDir = re.sub(r"\.\.\.$,", "", depotDir)
+ depotDir = re.sub(r"\.\.\.$", "", depotDir)
depotDir = re.sub(r"/$", "", depotDir)
return os.path.split(depotDir)[1]
if (!strcmp("smudge", ep)) {
if (!value)
- return error("%s: lacks value", var);
+ return config_error_nonbool(var);
drv->smudge = strdup(value);
return 0;
}
if (!strcmp("clean", ep)) {
if (!value)
- return error("%s: lacks value", var);
+ return config_error_nonbool(var);
drv->clean = strdup(value);
return 0;
}
return 0;
}
if (!strcmp(var, "diff.external")) {
+ if (!value)
+ return config_error_nonbool(var);
external_diff_cmd_cfg = xstrdup(value);
return 0;
}
const char *ep = strrchr(var, '.');
if (ep != var + 4) {
- if (!strcmp(ep, ".command"))
+ if (!strcmp(ep, ".command")) {
+ if (!value)
+ return config_error_nonbool(var);
return parse_lldiff_command(var, ep, value);
+ }
}
}
{
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
int slot = parse_diff_color_slot(var, 11);
+ if (!value)
+ return config_error_nonbool(var);
color_parse(value, var, diff_colors[slot]);
return 0;
}
if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.');
if (ep != var + 4) {
- if (!strcmp(ep, ".funcname"))
+ if (!strcmp(ep, ".funcname")) {
+ if (!value)
+ return config_error_nonbool(var);
return parse_funcname_pattern(var, ep, value);
+ }
}
}
static unsigned long max_depth = 10;
static off_t max_packsize = (1LL << 32) - 1;
static int force_update;
+static int pack_compression_level = Z_DEFAULT_COMPRESSION;
+static int pack_compression_seen;
/* Stats and misc. counters */
static uintmax_t alloc_count;
delta = NULL;
memset(&s, 0, sizeof(s));
- deflateInit(&s, zlib_compression_level);
+ deflateInit(&s, pack_compression_level);
if (delta) {
s.next_in = delta;
s.avail_in = deltalen;
delta = NULL;
memset(&s, 0, sizeof(s));
- deflateInit(&s, zlib_compression_level);
+ deflateInit(&s, pack_compression_level);
s.next_in = (void *)dat->buf;
s.avail_in = dat->len;
s.avail_out = deflateBound(&s, s.avail_in);
return 0;
}
+/* All calls must be guarded by find_object() or find_mark() to
+ * ensure the 'struct object_entry' passed was written by this
+ * process instance. We unpack the entry by the offset, avoiding
+ * the need for the corresponding .idx file. This unpacking rule
+ * works because we only use OBJ_REF_DELTA within the packfiles
+ * created by fast-import.
+ *
+ * oe must not be NULL. Such an oe usually comes from giving
+ * an unknown SHA-1 to find_object() or an undefined mark to
+ * find_mark(). Callers must test for this condition and use
+ * the standard read_sha1_file() when it happens.
+ *
+ * oe->pack_id must not be MAX_PACK_ID. Such an oe is usually from
+ * find_mark(), where the mark was reloaded from an existing marks
+ * file and is referencing an object that this fast-import process
+ * instance did not write out to a packfile. Callers must test for
+ * this condition and use read_sha1_file() instead.
+ */
static void *gfi_unpack_entry(
struct object_entry *oe,
unsigned long *sizep)
enum object_type type;
struct packed_git *p = all_packs[oe->pack_id];
if (p == pack_data && p->pack_size < (pack_size + 20)) {
+ /* The object is stored in the packfile we are writing to
+ * and we have modified it since the last time we scanned
+ * back to read a previously written object. If an old
+ * window covered [p->pack_size, p->pack_size + 20) its
+ * data is stale and is not valid. Closing all windows
+ * and updating the packfile length ensures we can read
+ * the newly written data.
+ */
close_pack_windows(p);
+
+ /* We have to offer 20 bytes additional on the end of
+ * the packfile as the core unpacker code assumes the
+ * footer is present at the file end and must promise
+ * at least 20 bytes within any window it maps. But
+ * we don't actually create the footer here.
+ */
p->pack_size = pack_size + 20;
}
return unpack_entry(p, oe->offset, &type, sizep);
fclose(f);
}
+static int git_pack_config(const char *k, const char *v)
+{
+ if (!strcmp(k, "pack.depth")) {
+ max_depth = git_config_int(k, v);
+ if (max_depth > MAX_DEPTH)
+ max_depth = MAX_DEPTH;
+ return 0;
+ }
+ if (!strcmp(k, "pack.compression")) {
+ int level = git_config_int(k, v);
+ if (level == -1)
+ level = Z_DEFAULT_COMPRESSION;
+ else if (level < 0 || level > Z_BEST_COMPRESSION)
+ die("bad pack compression level %d", level);
+ pack_compression_level = level;
+ pack_compression_seen = 1;
+ return 0;
+ }
+ return git_default_config(k, v);
+}
+
static const char fast_import_usage[] =
"git-fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
{
unsigned int i, show_stats = 1;
- git_config(git_default_config);
+ git_config(git_pack_config);
+ if (!pack_compression_seen && core_compression_seen)
+ pack_compression_level = core_compression_level;
+
alloc_objects(object_entry_alloc);
strbuf_init(&command_buf, 0);
atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*));
3,3way allow fall back on 3way merging if needed
s,signoff add a Signed-off-by line to the commit message
u,utf8 recode into utf8 (default)
-k,keep pass -k flagg to git-mailinfo
+k,keep pass -k flag to git-mailinfo
whitespace= pass it through git-apply
C= pass it through git-apply
p= pass it through git-apply
. git-sh-setup
require_work_tree
+_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
+_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+
sq() {
@@PERL@@ -e '
for (@ARGV) {
# top-of-line master first!
#
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) ||
- die "Bad HEAD - I need a symbolic ref"
+ head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
+ die "Bad HEAD - I need a HEAD"
case "$head" in
refs/heads/bisect)
if [ -s "$GIT_DIR/head-name" ]; then
fi
git checkout $branch || exit
;;
- refs/heads/*)
+ refs/heads/*|$_x40)
[ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
echo "${head#refs/heads/}" >"$GIT_DIR/head-name"
;;
done
arg="$1"
-if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
+rev=$(git rev-parse --verify "$arg" 2>/dev/null)
+if rev=$(git rev-parse --verify "$rev^0" 2>/dev/null)
then
[ -z "$rev" ] && die "unknown flag $arg"
new_name="$arg"
fi
new="$rev"
shift
-elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
+elif rev=$(git rev-parse --verify "$rev^{tree}" 2>/dev/null)
then
# checking out selected paths from a tree-ish.
new="$rev"
- new_name="$arg^{tree}"
+ new_name="$rev^{tree}"
shift
fi
[ "$1" = "--" ] && shift
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
+#ifndef NO_SYS_SELECT_H
#include <sys/select.h>
+#endif
#include <assert.h>
#include <regex.h>
#include <netinet/in.h>
if ($parent eq $lastpicked) {
next;
}
- my $base = safe_pipe_capture('git-merge-base',
+ my $base = eval {
+ safe_pipe_capture('git-merge-base',
$lastpicked, $parent);
+ };
+ # The two branches may not be related at all,
+ # in which case merge base simply fails to find
+ # any, but that's Ok.
+ next if ($@);
+
chomp $base;
if ($base) {
my @merged;
force=
while :
do
- test $# = 0 && usage
case "$1" in
--)
shift
workdir="$(pwd)" ||
die ""
+# Remove tempdir on exit
+trap 'cd ../..; rm -rf "$tempdir"' 0
+
# Make sure refs/original is empty
git for-each-ref > "$tempdir"/backup-refs
while read sha1 type name
export GIT_DIR GIT_WORK_TREE
# The refs should be updated if their heads were rewritten
-git rev-parse --no-flags --revs-only --symbolic-full-name "$@" |
+git rev-parse --no-flags --revs-only --symbolic-full-name --default HEAD "$@" |
sed -e '/^^/d' >"$tempdir"/heads
test -s "$tempdir"/heads ||
cd ../..
rm -rf "$tempdir"
+trap - 0
+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
test -z "$ORIG_GIT_DIR" || GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
test -z "$ORIG_GIT_WORK_TREE" || GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
QUIET_GEN = $(QUIET)echo ' ' GEN '$@' &&
QUIET_INDEX = $(QUIET)echo ' ' INDEX $(dir $@) &&
QUIET_MSGFMT0 = $(QUIET)printf ' MSGFMT %12s ' $@ && v=`
- QUIET_MSGFMT1 = 2>&1` && echo "$$v" | sed -e 's/fuzzy translations/fuzzy/' | sed -e 's/ messages//g'
+ QUIET_MSGFMT1 = 2>&1` && echo "$$v" | sed -e 's/fuzzy translations/fuzzy/' | sed -e 's/ messages*//g'
QUIET_2DEVNULL = 2>/dev/null
INSTALL_D0 = dir=
MSGFMT ?= $(TCL_PATH) po/po2msg.sh
else
MSGFMT ?= msgfmt
+ ifeq ($(shell $(MSGFMT) >/dev/null 2>&1 || echo $$?),127)
+ MSGFMT := $(TCL_PATH) po/po2msg.sh
+ endif
endif
msgsdir = $(gg_libdir)/msgs
return [open [concat $opt $cmdp $args] w]
}
+proc githook_read {hook_name args} {
+ set pchook [gitdir hooks $hook_name]
+ lappend args 2>@1
+
+ # On Cygwin [file executable] might lie so we need to ask
+ # the shell if the hook is executable. Yes that's annoying.
+ #
+ if {[is_Cygwin]} {
+ upvar #0 _sh interp
+ if {![info exists interp]} {
+ set interp [_which sh]
+ }
+ if {$interp eq {}} {
+ error "hook execution requires sh (not in PATH)"
+ }
+
+ set scr {if test -x "$1";then exec "$@";fi}
+ set sh_c [list | $interp -c $scr $interp $pchook]
+ return [_open_stdout_stderr [concat $sh_c $args]]
+ }
+
+ if {[file executable $pchook]} {
+ return [_open_stdout_stderr [concat [list | $pchook] $args]]
+ }
+
+ return {}
+}
+
proc sq {value} {
regsub -all ' $value "'\\''" value
return "'$value'"
focus $old_focus
}
}
- $sb set $first $last
+
+ catch {$sb set $first $last}
}
method _show_tooltip {pos} {
return
}
- # -- Run the pre-commit hook.
+ # -- Build the message file.
#
- set pchook [gitdir hooks pre-commit]
+ set msg_p [gitdir GITGUI_EDITMSG]
+ set msg_wt [open $msg_p w]
+ fconfigure $msg_wt -translation lf
+ if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
+ set enc utf-8
+ }
+ set use_enc [tcl_encoding $enc]
+ if {$use_enc ne {}} {
+ fconfigure $msg_wt -encoding $use_enc
+ } else {
+ puts stderr [mc "warning: Tcl does not support encoding '%s'." $enc]
+ fconfigure $msg_wt -encoding utf-8
+ }
+ puts $msg_wt $msg
+ close $msg_wt
- # On Cygwin [file executable] might lie so we need to ask
- # the shell if the hook is executable. Yes that's annoying.
+ # -- Run the pre-commit hook.
#
- if {[is_Cygwin] && [file isfile $pchook]} {
- set pchook [list sh -c [concat \
- "if test -x \"$pchook\";" \
- "then exec \"$pchook\" 2>&1;" \
- "fi"]]
- } elseif {[file executable $pchook]} {
- set pchook [list $pchook |& cat]
- } else {
- commit_writetree $curHEAD $msg
+ set fd_ph [githook_read pre-commit]
+ if {$fd_ph eq {}} {
+ commit_commitmsg $curHEAD $msg_p
return
}
ui_status {Calling pre-commit hook...}
set pch_error {}
- set fd_ph [open "| $pchook" r]
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
fileevent $fd_ph readable \
- [list commit_prehook_wait $fd_ph $curHEAD $msg]
+ [list commit_prehook_wait $fd_ph $curHEAD $msg_p]
}
-proc commit_prehook_wait {fd_ph curHEAD msg} {
+proc commit_prehook_wait {fd_ph curHEAD msg_p} {
global pch_error
append pch_error [read $fd_ph]
fconfigure $fd_ph -blocking 1
if {[eof $fd_ph]} {
if {[catch {close $fd_ph}]} {
+ catch {file delete $msg_p}
ui_status {Commit declined by pre-commit hook.}
hook_failed_popup pre-commit $pch_error
unlock_index
} else {
- commit_writetree $curHEAD $msg
+ commit_commitmsg $curHEAD $msg_p
}
set pch_error {}
return
fconfigure $fd_ph -blocking 0
}
-proc commit_writetree {curHEAD msg} {
+proc commit_commitmsg {curHEAD msg_p} {
+ global pch_error
+
+ # -- Run the commit-msg hook.
+ #
+ set fd_ph [githook_read commit-msg $msg_p]
+ if {$fd_ph eq {}} {
+ commit_writetree $curHEAD $msg_p
+ return
+ }
+
+ ui_status {Calling commit-msg hook...}
+ set pch_error {}
+ fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fileevent $fd_ph readable \
+ [list commit_commitmsg_wait $fd_ph $curHEAD $msg_p]
+}
+
+proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
+ global pch_error
+
+ append pch_error [read $fd_ph]
+ fconfigure $fd_ph -blocking 1
+ if {[eof $fd_ph]} {
+ if {[catch {close $fd_ph}]} {
+ catch {file delete $msg_p}
+ ui_status {Commit declined by commit-msg hook.}
+ hook_failed_popup commit-msg $pch_error
+ unlock_index
+ } else {
+ commit_writetree $curHEAD $msg_p
+ }
+ set pch_error {}
+ return
+ }
+ fconfigure $fd_ph -blocking 0
+}
+
+proc commit_writetree {curHEAD msg_p} {
ui_status {Committing changes...}
set fd_wt [git_read write-tree]
fileevent $fd_wt readable \
- [list commit_committree $fd_wt $curHEAD $msg]
+ [list commit_committree $fd_wt $curHEAD $msg_p]
}
-proc commit_committree {fd_wt curHEAD msg} {
+proc commit_committree {fd_wt curHEAD msg_p} {
global HEAD PARENT MERGE_HEAD commit_type
global current_branch
global ui_comm selected_commit_type
gets $fd_wt tree_id
if {[catch {close $fd_wt} err]} {
+ catch {file delete $msg_p}
error_popup [strcat [mc "write-tree failed:"] "\n\n$err"]
ui_status {Commit failed.}
unlock_index
}
if {$tree_id eq $old_tree} {
+ catch {file delete $msg_p}
info_popup [mc "No changes to commit.
No files were modified by this commit and it was not a merge commit.
}
}
- # -- Build the message.
- #
- set msg_p [gitdir COMMIT_EDITMSG]
- set msg_wt [open $msg_p w]
- fconfigure $msg_wt -translation lf
- if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
- set enc utf-8
- }
- set use_enc [tcl_encoding $enc]
- if {$use_enc ne {}} {
- fconfigure $msg_wt -encoding $use_enc
- } else {
- puts stderr [mc "warning: Tcl does not support encoding '%s'." $enc]
- fconfigure $msg_wt -encoding utf-8
- }
- puts $msg_wt $msg
- close $msg_wt
-
# -- Create the commit.
#
set cmd [list commit-tree $tree_id]
}
lappend cmd <$msg_p
if {[catch {set cmt_id [eval git $cmd]} err]} {
+ catch {file delete $msg_p}
error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"]
ui_status {Commit failed.}
unlock_index
if {$commit_type ne {normal}} {
append reflogm " ($commit_type)"
}
- set i [string first "\n" $msg]
- if {$i >= 0} {
- set subject [string range $msg 0 [expr {$i - 1}]]
- } else {
- set subject $msg
- }
+ set msg_fd [open $msg_p r]
+ gets $msg_fd subject
+ close $msg_fd
append reflogm {: } $subject
if {[catch {
git update-ref -m $reflogm HEAD $cmt_id $curHEAD
} err]} {
+ catch {file delete $msg_p}
error_popup [strcat [mc "update-ref failed:"] "\n\n$err"]
ui_status {Commit failed.}
unlock_index
# -- Run the post-commit hook.
#
- set pchook [gitdir hooks post-commit]
- if {[is_Cygwin] && [file isfile $pchook]} {
- set pchook [list sh -c [concat \
- "if test -x \"$pchook\";" \
- "then exec \"$pchook\";" \
- "fi"]]
- } elseif {![file executable $pchook]} {
- set pchook {}
- }
- if {$pchook ne {}} {
- catch {exec $pchook &}
+ set fd_ph [githook_read post-commit]
+ if {$fd_ph ne {}} {
+ upvar #0 pch_error$cmt_id pc_err
+ set pc_err {}
+ fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fileevent $fd_ph readable \
+ [list commit_postcommit_wait $fd_ph $cmt_id]
}
$ui_comm delete 0.0 end
reshow_diff
ui_status [mc "Created commit %s: %s" [string range $cmt_id 0 7] $subject]
}
+
+proc commit_postcommit_wait {fd_ph cmt_id} {
+ upvar #0 pch_error$cmt_id pch_error
+
+ append pch_error [read $fd_ph]
+ fconfigure $fd_ph -blocking 1
+ if {[eof $fd_ph]} {
+ if {[catch {close $fd_ph}]} {
+ hook_failed_popup post-commit $pch_error 0
+ }
+ unset pch_error
+ return
+ }
+ fconfigure $fd_ph -blocking 0
+}
eval $cmd
}
-proc hook_failed_popup {hook msg} {
+proc hook_failed_popup {hook msg {is_fatal 1}} {
set w .hookfail
toplevel $w
-width 80 -height 10 \
-font font_diff \
-yscrollcommand [list $w.m.sby set]
- label $w.m.l2 \
- -text [mc "You must correct the above errors before committing."] \
- -anchor w \
- -justify left \
- -font font_uibold
scrollbar $w.m.sby -command [list $w.m.t yview]
pack $w.m.l1 -side top -fill x
- pack $w.m.l2 -side bottom -fill x
+ if {$is_fatal} {
+ label $w.m.l2 \
+ -text [mc "You must correct the above errors before committing."] \
+ -anchor w \
+ -justify left \
+ -font font_uibold
+ pack $w.m.l2 -side bottom -fill x
+ }
pack $w.m.sby -side right -fill y
pack $w.m.t -side left -fill both -expand 1
pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
bind $w <Visibility> "grab $w; focus $w"
bind $w <Key-Return> "destroy $w"
- wm title $w [append "[appname] ([reponame]): " [mc "error"]]
+ wm title $w [strcat "[appname] ([reponame]): " [mc "error"]]
tkwait window $w
}
#. ""
msgid "branch [verb]"
-msgstr "créer une branche"
+msgstr "créer une branche"
#. ""
msgid "checkout [noun]"
#. ""
msgid "diff [noun]"
-msgstr "différence"
+msgstr "différence"
#. ""
msgid "diff [verb]"
#. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too."
msgid "fetch"
-msgstr "récupérer"
+msgstr "récupérer"
#. "A collection of files. The index is a stored version of your working tree."
msgid "index (in git-gui: staging area)"
-msgstr "pré-commit"
+msgstr "pré-commit"
#. "A successful merge results in the creation of a new commit representing the result of the merge."
msgid "merge [noun]"
#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
msgid "remote"
-msgstr "référentiel distant"
+msgstr "référentiel distant"
#. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)"
msgid "repository"
-msgstr "référentiel"
+msgstr "référentiel"
#. ""
msgid "reset"
-msgstr "réinitialiser"
+msgstr "réinitialiser"
#. ""
msgid "revert"
#. "A particular state of files and directories which was stored in the object database."
msgid "revision"
-msgstr "révision"
+msgstr "révision"
#. ""
msgid "sign off"
#. ""
msgid "staging area"
-msgstr "pré-commit"
+msgstr "pré-commit"
#. ""
msgid "status"
-msgstr "état"
+msgstr "état"
#. "A ref pointing to a tag or commit object"
msgid "tag [noun]"
#. ""
msgid "undo"
-msgstr "défaire"
+msgstr "défaire"
#. ""
msgid "update"
-msgstr "mise à jour"
+msgstr "mise à jour"
#. ""
msgid "verify"
-msgstr "vérifier"
+msgstr "vérifier"
#. "The tree of actual checked out files."
msgid "working copy, working tree"
}
if {$show_statistics} {
- puts [concat "$translated_count translated messages, " \
- "$fuzzy_count fuzzy ones, " \
- "$not_translated_count untranslated ones."]
+ set str ""
+
+ append str "$translated_count translated message"
+ if {$translated_count != 1} {
+ append str s
+ }
+
+ if {$fuzzy_count > 1} {
+ append str ", $fuzzy_count fuzzy translation"
+ if {$fuzzy_count != 1} {
+ append str s
+ }
+ }
+ if {$not_translated_count > 0} {
+ append str ", $not_translated_count untranslated message"
+ if {$not_translated_count != 1} {
+ append str s
+ }
+ }
+
+ append str .
+ puts $str
}
;;
esac
+init_browser_path() {
+ browser_path="`git config browser.$1.path`"
+ test -z "$browser_path" && browser_path="$1"
+}
+
start_httpd
url=http://127.0.0.1:$port
-test -n "$browser" && "$browser" $url || echo $url
+test -n "$browser" && {
+ init_browser_path "$browser"
+ "$browser_path" $url
+} || echo $url
exit 1
}
+test true = "$rebase" && {
+ . git-parse-remote &&
+ origin="$1"
+ test -z "$origin" && origin=$(get_default_remote)
+ reflist="$(get_remote_refs_for_fetch "$@" 2>/dev/null |
+ sed "s|refs/heads/\(.*\):|\1|")" &&
+ oldremoteref="$(git rev-parse --verify \
+ "refs/remotes/$origin/$reflist" 2>/dev/null)"
+}
orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
git-fetch --update-head-ok "$@" || exit 1
fi
merge_name=$(git fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
-test true = "$rebase" && exec git-rebase $merge_head
+test true = "$rebase" &&
+ exec git-rebase --onto $merge_head ${oldremoteref:-$merge_head}
exec git-merge $no_summary $no_commit $squash $no_ff $strategy_args \
"$merge_name" HEAD $merge_head
shift ;;
esac
;;
- --merge)
+ -m|--merge)
# we use merge anyway
;;
-C*)
opendir(D,$master_dir . "objects/")
or die "Failed to open $master_dir/objects/ : $!";
-my @hashdirs = grep !/^\.{1,2}$/, readdir(D);
+my @hashdirs = grep { ($_ eq 'pack') || /^[0-9a-f]{2}$/ } readdir(D);
foreach my $repo (@dirs) {
$linked = 0;
#!/usr/bin/perl -w
+use strict;
use Git;
my $git = Git->repository();
sub update_remote {
my ($name) = @_;
+ my @remotes;
my $conf = $git->config("remotes." . $name);
if (defined($conf)) {
@remotes = split(' ', $conf);
} elsif ($name eq 'default') {
- undef @remotes;
+ @remotes = ();
for (sort keys %$remote) {
my $do_fetch = $git->config_bool("remote." . $_ .
".skipDefaultUpdate");
my @refs = $git->command('for-each-ref',
'--format=%(refname) %(objectname)', "refs/remotes/$name");
for (@refs) {
- ($ref, $object) = split;
+ my ($ref, $object) = split;
$git->command(qw(update-ref -d), $ref, $object);
}
return 0;
exit(1);
}
-local $VERBOSE = 0;
+my $VERBOSE = 0;
@ARGV = grep {
if ($_ eq '-v' or $_ eq '--verbose') {
$VERBOSE=1;
update_remote("default");
exit(1);
}
- for ($i = 1; $i < @ARGV; $i++) {
+ for (my $i = 1; $i < @ARGV; $i++) {
update_remote($ARGV[$i]);
}
}
exit(0);
}
- @files = ($compose_filename . ".final");
+ @files = ($compose_filename . ".final", @files);
}
# Variables we set as part of the loop over files
. git-sh-setup
require_work_tree
-add=
+command=
branch=
-init=
-update=
-status=
quiet=
cached=
#
# Clone a submodule
#
-# Prior to calling, modules_update checks that a possibly existing
+# Prior to calling, cmd_update checks that a possibly existing
# path is not a git repository.
-# Likewise, module_add checks that path does not exist at all,
+# Likewise, cmd_add checks that path does not exist at all,
# since it is the location of a new submodule.
#
module_clone()
#
# optional branch is stored in global branch variable
#
-module_add()
+cmd_add()
{
+ # parse $args after "submodule ... add".
+ while test $# -ne 0
+ do
+ case "$1" in
+ -b | --branch)
+ case "$2" in '') usage ;; esac
+ branch=$2
+ shift
+ ;;
+ -q|--quiet)
+ quiet=1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
repo=$1
path=$2
#
# $@ = requested paths (default to all)
#
-modules_init()
+cmd_init()
{
+ # parse $args after "submodule ... init".
+ while test $# -ne 0
+ do
+ case "$1" in
+ -q|--quiet)
+ quiet=1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
git ls-files --stage -- "$@" | grep -e '^160000 ' |
while read mode sha1 stage path
do
#
# $@ = requested paths (default to all)
#
-modules_update()
+cmd_update()
{
+ # parse $args after "submodule ... update".
+ while test $# -ne 0
+ do
+ case "$1" in
+ -q|--quiet)
+ quiet=1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
git ls-files --stage -- "$@" | grep -e '^160000 ' |
while read mode sha1 stage path
do
#
# $@ = requested paths (default to all)
#
-modules_list()
+cmd_status()
{
+ # parse $args after "submodule ... status".
+ while test $# -ne 0
+ do
+ case "$1" in
+ -q|--quiet)
+ quiet=1
+ ;;
+ --cached)
+ cached=1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
git ls-files --stage -- "$@" | grep -e '^160000 ' |
while read mode sha1 stage path
do
done
}
-while test $# != 0
+# This loop parses the command line arguments to find the
+# subcommand name to dispatch. Parsing of the subcommand specific
+# options are primarily done by the subcommand implementations.
+# Subcommand specific options such as --branch and --cached are
+# parsed here as well, for backward compatibility.
+
+while test $# != 0 && test -z "$command"
do
case "$1" in
- add)
- add=1
- ;;
- init)
- init=1
- ;;
- update)
- update=1
- ;;
- status)
- status=1
+ add | init | update | status)
+ command=$1
;;
-q|--quiet)
quiet=1
shift
done
-case "$add,$branch" in
-1,*)
- ;;
-,)
- ;;
-,*)
+# No command word defaults to "status"
+test -n "$command" || command=status
+
+# "-b branch" is accepted only by "add"
+if test -n "$branch" && test "$command" != add
+then
usage
- ;;
-esac
-
-case "$add,$init,$update,$status,$cached" in
-1,,,,)
- module_add "$@"
- ;;
-,1,,,)
- modules_init "$@"
- ;;
-,,1,,)
- modules_update "$@"
- ;;
-,,,*,*)
- modules_list "$@"
- ;;
-*)
+fi
+
+# "--cached" is accepted only by "status"
+if test -n "$cached" && test "$command" != status
+then
usage
- ;;
-esac
+fi
+
+"cmd_$command" "$@"
"Show info about the latest SVN revision
on the current branch",
{ 'url' => \$_url, } ],
+ 'blame' => [ \&Git::SVN::Log::cmd_blame,
+ "Show what revision and author last modified each line of a file",
+ {} ],
);
my $cmd;
use File::Copy qw/copy/;
use IPC::Open3;
-my $_repack_nr;
+my ($_gc_nr, $_gc_period);
+
# properties that we do not log:
my %SKIP_PROP;
BEGIN {
}
sub init_vars {
- if (defined $_repack) {
- $_repack = 1000 if ($_repack <= 0);
- $_repack_nr = $_repack;
- $_repack_flags ||= '-d';
+ $_gc_nr = $_gc_period = 1000;
+ if (defined $_repack || defined $_repack_flags) {
+ warn "Repack options are obsolete; they have no effect.\n";
}
}
}
}
+sub gc {
+ command_noisy('gc', '--auto');
+};
+
sub do_git_commit {
my ($self, $log_entry) = @_;
my $lr = $self->last_rev;
0, $self->svm_uuid);
}
print " = $commit ($self->{ref_id})\n";
- if (defined $_repack && (--$_repack_nr == 0)) {
- $_repack_nr = $_repack;
- # repack doesn't use any arguments with spaces in them, does it?
- print "Running git repack $_repack_flags ...\n";
- command_noisy('repack', split(/\s+/, $_repack_flags));
- print "Done repacking\n";
+ if (--$_gc_nr == 0) {
+ $_gc_nr = $_gc_period;
+ gc();
}
return $commit;
}
# just grow a tail if we're not unique enough :x
$ref_id .= '-' while find_ref($ref_id);
print STDERR "Initializing parent: $ref_id\n";
- $gs = Git::SVN->init($new_url, '', $ref_id, $ref_id, 1);
+ my ($u, $p) = ($new_url, '');
+ if ($u =~ s#^\Q$url\E(/|$)##) {
+ $p = $u;
+ $u = $url;
+ }
+ $gs = Git::SVN->init($u, $p, $self->{repo_id}, $ref_id, 1);
}
my ($r0, $parent) = $gs->find_rev_before($r, 1);
if (!defined $r0 || !defined $parent) {
$max += $inc;
$max = $head if ($max > $head);
}
+ Git::SVN::gc();
}
sub match_globs {
print commit_log_separator unless $incremental || $oneline;
}
+sub cmd_blame {
+ my $path = shift;
+
+ config_pager();
+ run_pager();
+
+ my ($fh, $ctx) = command_output_pipe('blame', @_, $path);
+ while (my $line = <$fh>) {
+ if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
+ my (undef, $rev, undef) = ::cmt_metadata($1);
+ $rev = sprintf('%-10s', $rev);
+ $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
+ }
+ print $line;
+ }
+ command_close_pipe($fh, $ctx);
+}
+
package Git::SVN::Migration;
# these version numbers do NOT correspond to actual version numbers
# of git nor git-svn. They are just relative.
static int git_alias_config(const char *var, const char *value)
{
if (!prefixcmp(var, "alias.") && !strcmp(var + 6, alias_command)) {
+ if (!value)
+ return config_error_nonbool(var);
alias_string = xstrdup(value);
}
return 0;
Group: Development/Tools
URL: http://kernel.org/pub/software/scm/git/
Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
-BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
+BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: git-core = %{version}-%{release}
%{!?_without_docs: %doc Documentation/technical}
%changelog
+* Sun Feb 03 2008 James Bowes <jbowes@dangerouslyinc.com>
+- Add a BuildRequires for gettext
+
* Fri Jan 11 2008 Junio C Hamano <gitster@pobox.com>
- Include gitk message files
Gitweb config file variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You can set, among others, the following variables in gitweb config files:
+You can set, among others, the following variables in gitweb config files
+(with the exception of $projectroot and $projects_list this list does
+not include variables usually directly set during build):
* $GIT
Cure git executable to use. By default set to "$GIT_BINDIR/git", which
in turn is by default set to "$(bindir)/git". If you use git from binary
package, set this to "/usr/bin/git". This can just be "git" if your
webserver has a sensible PATH. If you have multiple git versions
- installed it is / can be used to choose which one to use.
+ installed it can be used to choose which one to use.
* $version
Gitweb version, set automatically when creating gitweb.cgi from
gitweb.perl. You might want to modify it if you are running modified
gitweb.
+ * $projectroot
+ Absolute filesystem path which will be prepended to project path;
+ the path to repository is $projectroot/$project. Set to
+ $GITWEB_PROJECTROOT during installation. This variable have to be
+ set correctly for gitweb to find repositories.
+ * $projects_list
+ Source of projects list, either directory to scan, or text file
+ with list of repositories (in the "<URI-encoded repository path> SPC
+ <URI-encoded repository owner>" format). Set to $GITWEB_LIST
+ during installation. If empty, $projectroot is used to scan for
+ repositories.
* $my_url, $my_uri
URL and absolute URL of gitweb script; you might need to set those
variables if you are using 'pathinfo' feature: see also below.
my $path = shift;
$git_dir = "$projectroot/$path";
- open my $fd, "$projectroot/$path/description"
+ open my $fd, "$git_dir/description"
or return git_get_project_config('description');
my $descr = <$fd>;
close $fd;
my $path = shift;
$git_dir = "$projectroot/$path";
- open my $fd, "$projectroot/$path/cloneurl"
+ open my $fd, "$git_dir/cloneurl"
or return wantarray ?
@{ config_to_multi(git_get_project_config('url')) } :
config_to_multi(git_get_project_config('url'));
-expires => $expires,
-content_disposition => 'inline; filename="' . "$filename" . '"');
my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
- print <<TEXT;
-From: $co{'author'}
-Date: $ad{'rfc2822'} ($ad{'tz_local'})
-Subject: $co{'title'}
-TEXT
+ print "From: " . to_utf8($co{'author'}) . "\n";
+ print "Date: $ad{'rfc2822'} ($ad{'tz_local'})\n";
+ print "Subject: " . to_utf8($co{'title'}) . "\n";
+
print "X-Git-Tag: $tagname\n" if $tagname;
print "X-Git-Url: " . $cgi->self_url() . "\n\n";
foreach my $line (@{$co{'comment'}}) {
- print "$line\n";
+ print to_utf8($line) . "\n";
}
print "---\n\n";
}
or next;
# print element (entry, item)
- my $co_url = href(-full=>1, action=>"commit", hash=>$commit);
+ my $co_url = href(-full=>1, action=>"commitdiff", hash=>$commit);
if ($format eq 'rss') {
print "<item>\n" .
"<title>" . esc_html($co{'title'}) . "</title>\n" .
static int git_help_config(const char *var, const char *value)
{
if (!strcmp(var, "help.format")) {
+ if (!value)
+ return config_error_nonbool(var);
help_default_format = xstrdup(value);
return 0;
}
if (!strcmp("http.sslcert", var)) {
if (ssl_cert == NULL) {
- ssl_cert = xmalloc(strlen(value)+1);
- strcpy(ssl_cert, value);
+ if (!value)
+ return config_error_nonbool(var);
+ ssl_cert = xstrdup(value);
}
return 0;
}
#if LIBCURL_VERSION_NUM >= 0x070902
if (!strcmp("http.sslkey", var)) {
if (ssl_key == NULL) {
- ssl_key = xmalloc(strlen(value)+1);
- strcpy(ssl_key, value);
+ if (!value)
+ return config_error_nonbool(var);
+ ssl_key = xstrdup(value);
}
return 0;
}
#if LIBCURL_VERSION_NUM >= 0x070908
if (!strcmp("http.sslcapath", var)) {
if (ssl_capath == NULL) {
- ssl_capath = xmalloc(strlen(value)+1);
- strcpy(ssl_capath, value);
+ if (!value)
+ return config_error_nonbool(var);
+ ssl_capath = xstrdup(value);
}
return 0;
}
#endif
if (!strcmp("http.sslcainfo", var)) {
if (ssl_cainfo == NULL) {
- ssl_cainfo = xmalloc(strlen(value)+1);
- strcpy(ssl_cainfo, value);
+ if (!value)
+ return config_error_nonbool(var);
+ ssl_cainfo = xstrdup(value);
}
return 0;
}
}
if (!strcmp("http.proxy", var)) {
if (curl_http_proxy == NULL) {
- curl_http_proxy = xmalloc(strlen(value)+1);
- strcpy(curl_http_proxy, value);
+ if (!value)
+ return config_error_nonbool(var);
+ curl_http_proxy = xstrdup(value);
}
return 0;
}
#include "strbuf.h"
+/*
+ * We detect based on the cURL version if multi-transfer is
+ * usable in this implementation and define this symbol accordingly.
+ * This is not something Makefile should set nor users should pass
+ * via CFLAGS.
+ */
+#undef USE_CURL_MULTI
+
#if LIBCURL_VERSION_NUM >= 0x071000
#define USE_CURL_MULTI
#define DEFAULT_MAX_REQUESTS 5
if (strncmp( key, imap_key, sizeof imap_key - 1 ))
return 0;
+
+ if (!val)
+ return config_error_nonbool(key);
+
key += sizeof imap_key - 1;
if (!strcmp( "folder", key )) {
int namelen;
if (!strcmp(var, "merge.default")) {
- if (value)
- default_ll_merge = strdup(value);
+ if (!value)
+ return config_error_nonbool(var);
+ default_ll_merge = strdup(value);
return 0;
}
if (!strcmp("name", ep)) {
if (!value)
- return error("%s: lacks value", var);
+ return config_error_nonbool(var);
fn->description = strdup(value);
return 0;
}
if (!strcmp("driver", ep)) {
if (!value)
- return error("%s: lacks value", var);
+ return config_error_nonbool(var);
/*
* merge.<name>.driver specifies the command line:
*
if (!strcmp("recursive", ep)) {
if (!value)
- return error("%s: lacks value", var);
+ return config_error_nonbool(var);
fn->recursive = strdup(value);
return 0;
}
if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(sha1);
if (blob) {
- parse_blob_buffer(blob, buffer, size);
+ if (parse_blob_buffer(blob, buffer, size))
+ return NULL;
obj = &blob->object;
}
} else if (type == OBJ_TREE) {
if (tree) {
obj = &tree->object;
if (!tree->object.parsed) {
- parse_tree_buffer(tree, buffer, size);
+ if (parse_tree_buffer(tree, buffer, size))
+ return NULL;
eaten = 1;
}
}
} else if (type == OBJ_COMMIT) {
struct commit *commit = lookup_commit(sha1);
if (commit) {
- parse_commit_buffer(commit, buffer, size);
+ if (parse_commit_buffer(commit, buffer, size))
+ return NULL;
if (!commit->buffer) {
commit->buffer = buffer;
eaten = 1;
} else if (type == OBJ_TAG) {
struct tag *tag = lookup_tag(sha1);
if (tag) {
- parse_tag_buffer(tag, buffer, size);
+ if (parse_tag_buffer(tag, buffer, size))
+ return NULL;
obj = &tag->object;
}
} else {
return error("unknown option `%s'", arg);
}
+void check_typos(const char *arg, const struct option *options)
+{
+ if (strlen(arg) < 3)
+ return;
+
+ if (!prefixcmp(arg, "no-")) {
+ error ("did you mean `--%s` (with two dashes ?)", arg);
+ exit(129);
+ }
+
+ for (; options->type != OPTION_END; options++) {
+ if (!options->long_name)
+ continue;
+ if (!prefixcmp(options->long_name, arg)) {
+ error ("did you mean `--%s` (with two dashes ?)", arg);
+ exit(129);
+ }
+ }
+}
+
static NORETURN void usage_with_options_internal(const char * const *,
const struct option *, int);
if (arg[1] != '-') {
args.opt = arg + 1;
- do {
+ if (*args.opt == 'h')
+ usage_with_options(usagestr, options);
+ if (parse_short_opt(&args, options) < 0)
+ usage_with_options(usagestr, options);
+ if (args.opt)
+ check_typos(arg + 1, options);
+ while (args.opt) {
if (*args.opt == 'h')
usage_with_options(usagestr, options);
if (parse_short_opt(&args, options) < 0)
usage_with_options(usagestr, options);
- } while (args.opt);
+ }
continue;
}
subkey = strrchr(name, '.');
if (!subkey)
return 0;
- if (!value)
- return 0;
branch = make_branch(name, subkey - name);
if (!strcmp(subkey, ".remote")) {
+ if (!value)
+ return config_error_nonbool(key);
branch->remote_name = xstrdup(value);
if (branch == current_branch)
default_remote_name = branch->remote_name;
- } else if (!strcmp(subkey, ".merge"))
+ } else if (!strcmp(subkey, ".merge")) {
+ if (!value)
+ return config_error_nonbool(key);
add_merge(branch, xstrdup(value));
+ }
return 0;
}
if (prefixcmp(key, "remote."))
if (is_bare_repository_cfg == 1)
inside_work_tree = -1;
} else if (strcmp(var, "core.worktree") == 0) {
+ if (!value)
+ return config_error_nonbool(var);
if (git_work_tree_cfg)
free(git_work_tree_cfg);
git_work_tree_cfg = xstrdup(value);
--- /dev/null
+* -whitespace
- test_expect_failure <message> <script>
- This is the opposite of test_expect_success. If <script>
- yields success, test is considered a failure.
-
- Example:
-
- test_expect_failure \
- 'git-update-index without --add should fail adding.' \
- 'git-update-index should-be-empty'
+ This is NOT the opposite of test_expect_success, but is used
+ to mark a test that demonstrates a known breakage. Unlike
+ the usual test_expect_success tests, which say "ok" on
+ success and "FAIL" on failure, this will say "FIXED" on
+ success and "still broken" on failure. Failures from these
+ tests won't cause -i (immediate) to stop.
- test_debug <script>
'.git/objects should have 3 subdirectories.' \
'test $(wc -l < full-of-directories) = 3'
+################################################################
+# Test harness
+test_expect_success 'success is reported like this' '
+ :
+'
+test_expect_failure 'pretend we have a known breakage' '
+ false
+'
+test_expect_failure 'pretend we have fixed a known breakage' '
+ :
+'
+
################################################################
# Basics of the basics
# updating a new file without --add should fail.
-test_expect_failure \
- 'git update-index without --add should fail adding.' \
- 'git update-index should-be-empty'
+test_expect_success 'git update-index without --add should fail adding.' '
+ ! git update-index should-be-empty
+'
# and with --add it should succeed, even if it is empty (it used to fail).
test_expect_success \
# Removing paths.
rm -f should-be-empty full-of-directories
-test_expect_failure \
- 'git update-index without --remove should fail removing.' \
- 'git update-index should-be-empty'
+test_expect_success 'git update-index without --remove should fail removing.' '
+ ! git update-index should-be-empty
+'
test_expect_success \
'git update-index with --remove should be able to remove.' \
'put invalid objects into the index.' \
'git update-index --index-info < badobjects'
-test_expect_failure \
- 'writing this tree without --missing-ok.' \
- 'git write-tree'
+test_expect_success 'writing this tree without --missing-ok.' '
+ ! git write-tree
+'
test_expect_success \
'writing this tree with --missing-ok.' \
--- /dev/null
+#!/bin/sh
+
+test_description=gitattributes
+
+. ./test-lib.sh
+
+attr_check () {
+
+ path="$1"
+ expect="$2"
+
+ git check-attr test -- "$path" >actual &&
+ echo "$path: test: $2" >expect &&
+ diff -u expect actual
+
+}
+
+
+test_expect_success 'setup' '
+
+ mkdir -p a/b/d a/c &&
+ (
+ echo "f test=f"
+ ) >.gitattributes &&
+ (
+ echo "g test=a/g" &&
+ echo "b/g test=a/b/g"
+ ) >a/.gitattributes &&
+ (
+ echo "h test=a/b/h" &&
+ echo "d/* test=a/b/d/*"
+ ) >a/b/.gitattributes
+
+'
+
+test_expect_success 'attribute test' '
+
+ attr_check f f &&
+ attr_check a/f f &&
+ attr_check a/c/f f &&
+ attr_check a/g a/g &&
+ attr_check a/b/g a/b/g &&
+ attr_check b/g unspecified &&
+ attr_check a/b/h a/b/h &&
+ attr_check a/b/d/g "a/b/d/*"
+
+'
+
+test_done
test `printf "$ttt$sss$sss$sss" | git stripspace | wc -l` -gt 0
'
-test_expect_failure \
+test_expect_success \
'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 " "
+ ! (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 \
git diff expect actual
'
-test_expect_failure \
+test_expect_success \
'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 " "
+ ! (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 \
git diff expect actual
'
-test_expect_failure \
+test_expect_success \
'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 " "
+ ! (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 \
get a string
--string2 <str> get another string
--st <st> get another string (pervert ordering)
+ -o <str> get another string
EOF
git diff expect output
'
-test_expect_failure 'ambiguously abbreviated option' '
+test_expect_success 'ambiguously abbreviated option' '
test-parse-options --strin 123;
- test $? != 129
+ test $? = 129
'
cat > expect << EOF
git diff expect output
'
+cat > expect.err << EOF
+error: did you mean \`--boolean\` (with two dashes ?)
+EOF
+
+test_expect_success 'detect possible typos' '
+ ! test-parse-options -boolean > output 2> output.err &&
+ test ! -s output &&
+ git diff expect.err output.err
+'
+
test_done
END_OF_CASE_TABLE
-test_expect_failure \
- '1 - must not have an entry not in A.' \
- "rm -f .git/index XX &&
+test_expect_success '1 - must not have an entry not in A.' "
+ rm -f .git/index XX &&
echo XX >XX &&
git update-index --add XX &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'2 - must match B in !O && !A && B case.' \
echo extra >>AN &&
git read-tree -m $tree_O $tree_A $tree_B"
-test_expect_failure \
- '3 (fail) - must match A in !O && A && !B case.' \
- "rm -f .git/index AN &&
+test_expect_success \
+ '3 (fail) - must match A in !O && A && !B case.' "
+ rm -f .git/index AN &&
cp .orig-A/AN AN &&
echo extra >>AN &&
git update-index --add AN &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'4 - must match and be up-to-date in !O && A && B && A!=B case.' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' \
- "rm -f .git/index AA &&
+test_expect_success \
+ '4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' "
+ rm -f .git/index AA &&
cp .orig-A/AA AA &&
git update-index --add AA &&
echo extra >>AA &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' \
- "rm -f .git/index AA &&
+test_expect_success \
+ '4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' "
+ rm -f .git/index AA &&
cp .orig-A/AA AA &&
echo extra >>AA &&
git update-index --add AA &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'5 - must match in !O && A && B && A==B case.' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '5 (fail) - must match A in !O && A && B && A==B case.' \
- "rm -f .git/index LL &&
+test_expect_success \
+ '5 (fail) - must match A in !O && A && B && A==B case.' "
+ rm -f .git/index LL &&
cp .orig-A/LL LL &&
echo extra >>LL &&
git update-index --add LL &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '6 - must not exist in O && !A && !B case' \
- "rm -f .git/index DD &&
+test_expect_success \
+ '6 - must not exist in O && !A && !B case' "
+ rm -f .git/index DD &&
echo DD >DD
git update-index --add DD &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '7 - must not exist in O && !A && B && O!=B case' \
- "rm -f .git/index DM &&
+test_expect_success \
+ '7 - must not exist in O && !A && B && O!=B case' "
+ rm -f .git/index DM &&
cp .orig-B/DM DM &&
git update-index --add DM &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '8 - must not exist in O && !A && B && O==B case' \
- "rm -f .git/index DN &&
+test_expect_success \
+ '8 - must not exist in O && !A && B && O==B case' "
+ rm -f .git/index DN &&
cp .orig-B/DN DN &&
git update-index --add DN &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'9 - must match and be up-to-date in O && A && !B && O!=A case' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' \
- "rm -f .git/index MD &&
+test_expect_success \
+ '9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' "
+ rm -f .git/index MD &&
cp .orig-A/MD MD &&
git update-index --add MD &&
echo extra >>MD &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' \
- "rm -f .git/index MD &&
+test_expect_success \
+ '9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' "
+ rm -f .git/index MD &&
cp .orig-A/MD MD &&
echo extra >>MD &&
git update-index --add MD &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'10 - must match and be up-to-date in O && A && !B && O==A case' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '10 (fail) - must match and be up-to-date in O && A && !B && O==A case' \
- "rm -f .git/index ND &&
+test_expect_success \
+ '10 (fail) - must match and be up-to-date in O && A && !B && O==A case' "
+ rm -f .git/index ND &&
cp .orig-A/ND ND &&
git update-index --add ND &&
echo extra >>ND &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '10 (fail) - must match and be up-to-date in O && A && !B && O==A case' \
- "rm -f .git/index ND &&
+test_expect_success \
+ '10 (fail) - must match and be up-to-date in O && A && !B && O==A case' "
+ rm -f .git/index ND &&
cp .orig-A/ND ND &&
echo extra >>ND &&
git update-index --add ND &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'11 - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
- "rm -f .git/index MM &&
+test_expect_success \
+ '11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' "
+ rm -f .git/index MM &&
cp .orig-A/MM MM &&
git update-index --add MM &&
echo extra >>MM &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
- "rm -f .git/index MM &&
+test_expect_success \
+ '11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' "
+ rm -f .git/index MM &&
cp .orig-A/MM MM &&
echo extra >>MM &&
git update-index --add MM &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'12 - must match A in O && A && B && O!=A && A==B case' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '12 (fail) - must match A in O && A && B && O!=A && A==B case' \
- "rm -f .git/index SS &&
+test_expect_success \
+ '12 (fail) - must match A in O && A && B && O!=A && A==B case' "
+ rm -f .git/index SS &&
cp .orig-A/SS SS &&
echo extra >>SS &&
git update-index --add SS &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'13 - must match A in O && A && B && O!=A && O==B case' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
- "rm -f .git/index NM &&
+test_expect_success \
+ '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' "
+ rm -f .git/index NM &&
cp .orig-A/NM NM &&
git update-index --add NM &&
echo extra >>NM &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
-test_expect_failure \
- '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
- "rm -f .git/index NM &&
+test_expect_success \
+ '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' "
+ rm -f .git/index NM &&
cp .orig-A/NM NM &&
echo extra >>NM &&
git update-index --add NM &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
test_expect_success \
'15 - must match A in O && A && B && O==A && O==B case' \
git read-tree -m $tree_O $tree_A $tree_B &&
check_result"
-test_expect_failure \
- '15 (fail) - must match A in O && A && B && O==A && O==B case' \
- "rm -f .git/index NN &&
+test_expect_success \
+ '15 (fail) - must match A in O && A && B && O==A && O==B case' "
+ rm -f .git/index NN &&
cp .orig-A/NN NN &&
echo extra >>NN &&
git update-index --add NN &&
- git read-tree -m $tree_O $tree_A $tree_B"
+ ! git read-tree -m $tree_O $tree_A $tree_B
+"
# #16
test_expect_success \
echo "Lots of fun" >>example
git commit -m 'Some fun.' -i hello example
-test_expect_failure 'git resolve now fails' '
- git merge -m "Merge work in mybranch" mybranch
+test_expect_success 'git resolve now fails' '
+ ! git merge -m "Merge work in mybranch" mybranch
'
cat > hello << EOF
test_expect_success 'git repack' 'git repack'
test_expect_success 'git prune-packed' 'git prune-packed'
-test_expect_failure '-> only packed objects' 'find -type f .git/objects/[0-9a-f][0-9a-f]'
+test_expect_success '-> only packed objects' '
+ ! find -type f .git/objects/[0-9a-f][0-9a-f]
+'
test_done
test_expect_success 'non-match result' 'cmp .git/config expect'
+cat > .git/config <<\EOF
+[alpha]
+bar = foo
+[beta]
+baz = multiple \
+lines
+EOF
+
+test_expect_success 'unset with cont. lines' \
+ 'git config --unset beta.baz'
+
+cat > expect <<\EOF
+[alpha]
+bar = foo
+[beta]
+EOF
+
+test_expect_success 'unset with cont. lines is correct' 'cmp .git/config expect'
+
cat > .git/config << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
test_expect_success 'non-match value' \
'test wow = $(git config --get nextsection.nonewline !for)'
-test_expect_failure 'ambiguous get' \
- 'git config --get nextsection.nonewline'
+test_expect_success 'ambiguous get' '
+ ! git config --get nextsection.nonewline
+'
test_expect_success 'get multivar' \
'git config --get-all nextsection.nonewline'
test_expect_success 'multivar replace' 'cmp .git/config expect'
-test_expect_failure 'ambiguous value' 'git config nextsection.nonewline'
+test_expect_success 'ambiguous value' '
+ ! git config nextsection.nonewline
+'
-test_expect_failure 'ambiguous unset' \
- 'git config --unset nextsection.nonewline'
+test_expect_success 'ambiguous unset' '
+ ! git config --unset nextsection.nonewline
+'
-test_expect_failure 'invalid unset' \
- 'git config --unset somesection.nonewline'
+test_expect_success 'invalid unset' '
+ ! git config --unset somesection.nonewline
+'
git config --unset nextsection.nonewline "wow3$"
test_expect_success 'multivar unset' 'cmp .git/config expect'
-test_expect_failure 'invalid key' 'git config inval.2key blabla'
+test_expect_success 'invalid key' '! git config inval.2key blabla'
test_expect_success 'correct key' 'git config 123456.a123 987'
cat > .git/config << EOF
[novalue]
variable
+[emptyvalue]
+ variable =
EOF
test_expect_success 'get variable with no value' \
'git config --get novalue.variable ^$'
+test_expect_success 'get variable with empty value' \
+ 'git config --get emptyvalue.variable ^$'
+
echo novalue.variable > expect
test_expect_success 'get-regexp variable with no value' \
'git config --get-regexp novalue > output &&
cmp output expect'
+echo 'emptyvalue.variable ' > expect
+
+test_expect_success 'get-regexp variable with empty value' \
+ 'git config --get-regexp emptyvalue > output &&
+ cmp output expect'
+
+echo true > expect
+
+test_expect_success 'get bool variable with no value' \
+ 'git config --bool novalue.variable > output &&
+ cmp output expect'
+
+echo false > expect
+
+test_expect_success 'get bool variable with empty value' \
+ 'git config --bool emptyvalue.variable > output &&
+ cmp output expect'
+
git config > output 2>&1
test_expect_success 'no arguments, but no crash' \
test_expect_success "rename succeeded" "git diff expect .git/config"
-test_expect_failure "rename non-existing section" \
- 'git config --rename-section branch."world domination" branch.drei'
+test_expect_success "rename non-existing section" '
+ ! git config --rename-section branch."world domination" branch.drei
+'
test_expect_success "rename succeeded" "git diff expect .git/config"
done &&
cmp expect result'
-test_expect_failure 'invalid bool (--get)' '
+test_expect_success 'invalid bool (--get)' '
git config bool.nobool foobar &&
- git config --bool --get bool.nobool'
+ ! git config --bool --get bool.nobool'
-test_expect_failure 'invalid bool (set)' '
+test_expect_success 'invalid bool (set)' '
- git config --bool bool.nobool foobar'
+ ! git config --bool bool.nobool foobar'
rm .git/config
test_expect_success 'quoting' 'cmp .git/config expect'
-test_expect_failure 'key with newline' 'git config key.with\\\
-newline 123'
+test_expect_success 'key with newline' '
+ ! git config "key.with
+newline" 123'
test_expect_success 'value with newline' 'git config key.sub value.with\\\
newline'
(git apply --check --index test.patch &&
cd test && git apply --check --index ../test.patch)'
-test_expect_failure 'gitdir required mode on unsupported repo' '
- (cd test2 && git apply --check --index ../test.patch)'
+test_expect_success 'gitdir required mode on unsupported repo' '
+ (cd test2 && ! git apply --check --index ../test.patch)
+'
test_done
test $B"' = $(cat .git/'"$m"')'
rm -f .git/$m
-test_expect_failure \
- '(not) create HEAD with old sha1' \
- "git update-ref HEAD $A $B"
-test_expect_failure \
- "(not) prior created .git/$m" \
- "test -f .git/$m"
+test_expect_success '(not) create HEAD with old sha1' "
+ ! git update-ref HEAD $A $B
+"
+test_expect_success "(not) prior created .git/$m" "
+ ! test -f .git/$m
+"
rm -f .git/$m
test_expect_success \
"create HEAD" \
"git update-ref HEAD $A"
-test_expect_failure \
- '(not) change HEAD with wrong SHA1' \
- "git update-ref HEAD $B $Z"
-test_expect_failure \
- "(not) changed .git/$m" \
- "test $B"' = $(cat .git/'"$m"')'
+test_expect_success '(not) change HEAD with wrong SHA1' "
+ ! git update-ref HEAD $B $Z
+"
+test_expect_success "(not) changed .git/$m" "
+ ! test $B"' = $(cat .git/'"$m"')
+'
rm -f .git/$m
: a repository with working tree always has reflog these days...
date >path0/file0
date >path1
-test_expect_failure \
+test_expect_success \
'git checkout-index without -f should fail on conflicting work tree.' \
- 'git checkout-index -a'
+ '! git checkout-index -a'
test_expect_success \
'git checkout-index with -f should succeed.' \
git update-index --add path0 &&
t=$(git write-tree)'
-test_expect_failure \
+test_expect_success \
'without -u, git checkout-index smudges stat information.' '
rm -f path0 &&
git read-tree $t &&
git checkout-index -f -a &&
-git diff-files | diff - /dev/null'
+! git diff-files | diff - /dev/null'
test_expect_success \
'with -u, git checkout-index picks up stat information from new files.' '
'
-test_expect_failure 'relative path outside tree should fail' \
- 'git checkout HEAD -- ../../Makefile'
+test_expect_success 'relative path outside tree should fail' \
+ '! git checkout HEAD -- ../../Makefile'
-test_expect_failure 'incorrect relative path to file should fail (1)' \
- 'git checkout HEAD -- ../file0'
+test_expect_success 'incorrect relative path to file should fail (1)' \
+ '! git checkout HEAD -- ../file0'
-test_expect_failure 'incorrect relative path should fail (2)' \
- '( cd dir1 && git checkout HEAD -- ./file0 )'
+test_expect_success 'incorrect relative path should fail (2)' \
+ '( cd dir1 && ! git checkout HEAD -- ./file0 )'
-test_expect_failure 'incorrect relative path should fail (3)' \
- '( cd dir1 && git checkout HEAD -- ../../file0 )'
+test_expect_success 'incorrect relative path should fail (3)' \
+ '( cd dir1 && ! git checkout HEAD -- ../../file0 )'
test_done
for p in path0/file0 path1/file1 path2 path3
do
- test_expect_failure \
+ test_expect_success \
"git update-index to add conflicting path $p should fail." \
- "git update-index --add -- $p"
+ "! git update-index --add -- $p"
done
test_done
git update-index --add foo bar
git-commit -m "add foo bar"
-test_expect_failure \
+test_expect_success \
'git ls-files --error-unmatch should fail with unmatched path.' \
- 'git ls-files --error-unmatch foo bar-does-not-match'
+ '! git ls-files --error-unmatch foo bar-does-not-match'
test_expect_success \
'git ls-files --error-unmatch should succeed eith matched paths.' \
git-commit -m "Initial commit." &&
HEAD=$(git rev-parse --verify HEAD)'
-test_expect_failure \
- 'git branch --help should not have created a bogus branch' \
- 'git branch --help </dev/null >/dev/null 2>/dev/null || :
- test -f .git/refs/heads/--help'
+test_expect_success \
+ 'git branch --help should not have created a bogus branch' '
+ git branch --help </dev/null >/dev/null 2>/dev/null;
+ ! test -f .git/refs/heads/--help
+'
test_expect_success \
'git branch abc should create a branch' \
git branch -m n/n n
test -f .git/logs/refs/heads/n'
-test_expect_failure \
- 'git branch -m o/o o should fail when o/p exists' \
- 'git branch o/o &&
+test_expect_success 'git branch -m o/o o should fail when o/p exists' '
+ git branch o/o &&
git branch o/p &&
- git branch -m o/o o'
+ ! git branch -m o/o o
+'
-test_expect_failure \
- 'git branch -m q r/q should fail when r exists' \
- 'git branch q &&
- git branch r &&
- git branch -m q r/q'
+test_expect_success 'git branch -m q r/q should fail when r exists' '
+ git branch q &&
+ git branch r &&
+ ! git branch -m q r/q
+'
mv .git/config .git/config-saved
"test $(git config branch.s.dummy) = Hello &&
! git config branch.s/s/dummy"
-test_expect_failure \
- 'git branch -m u v should fail when the reflog for u is a symlink' \
- 'git branch -l u &&
+test_expect_success \
+ 'git branch -m u v should fail when the reflog for u is a symlink' '
+ git branch -l u &&
mv .git/logs/refs/heads/u real-u &&
ln -s real-u .git/logs/refs/heads/u &&
- git branch -m u v'
+ ! git branch -m u v
+'
test_expect_success 'test tracking setup via --track' \
'git config remote.local.url . &&
git show-ref b >result &&
diff expect result'
-test_expect_failure \
- 'git branch c/d should barf if branch c exists' \
- 'git branch c &&
+test_expect_success 'git branch c/d should barf if branch c exists' '
+ git branch c &&
git pack-refs --all &&
- rm .git/refs/heads/c &&
- git branch c/d'
+ rm -f .git/refs/heads/c &&
+ ! git branch c/d
+'
test_expect_success \
'see if a branch still exists after git pack-refs --prune' \
git show-ref e >result &&
diff expect result'
-test_expect_failure \
- 'see if git pack-refs --prune remove ref files' \
- 'git branch f &&
+test_expect_success 'see if git pack-refs --prune remove ref files' '
+ git branch f &&
git pack-refs --all --prune &&
- ls .git/refs/heads/f'
+ ! test -f .git/refs/heads/f
+'
test_expect_success \
'git branch g should work when git branch g/h has been deleted' \
git pack-refs --all &&
git branch -d g'
-test_expect_failure \
- 'git branch i/j/k should barf if branch i exists' \
- 'git branch i &&
+test_expect_success 'git branch i/j/k should barf if branch i exists' '
+ git branch i &&
git pack-refs --all --prune &&
- git branch i/j/k'
+ ! git branch i/j/k
+'
test_expect_success \
'test git branch k after branch k/l/m and k/lm have been deleted' \
test_expect_success 'rebase against master' '
git rebase master'
-test_expect_failure \
+test_expect_success \
'the rebase operation should not have destroyed author information' \
- 'git log | grep "Author:" | grep "<>"'
+ '! git log | grep "Author:" | grep "<>"'
test_expect_success 'rebase after merge master' '
git reset --hard topic &&
git branch skip-merge skip-reference
'
-test_expect_failure 'rebase with git am -3 (default)' '
- git rebase master
+test_expect_success 'rebase with git am -3 (default)' '
+ ! git rebase master
'
test_expect_success 'rebase --skip with am -3' '
test_expect_success 'checkout skip-merge' 'git checkout -f skip-merge'
-test_expect_failure 'rebase with --merge' 'git rebase --merge master'
+test_expect_success 'rebase with --merge' '! git rebase --merge master'
test_expect_success 'rebase --skip with --merge' '
git rebase --skip
test $grandparent = $(git rev-parse HEAD~2)
'
+test_expect_success 'rebase a commit violating pre-commit' '
+
+ mkdir -p .git/hooks &&
+ PRE_COMMIT=.git/hooks/pre-commit &&
+ echo "#!/bin/sh" > $PRE_COMMIT &&
+ echo "test -z \"\$(git diff --cached --check)\"" >> $PRE_COMMIT &&
+ chmod a+x $PRE_COMMIT &&
+ echo "monde! " >> file1 &&
+ test_tick &&
+ ! git commit -m doesnt-verify file1 &&
+ git commit -m doesnt-verify --no-verify file1 &&
+ test_tick &&
+ FAKE_LINES=2 git rebase -i HEAD~2
+
+'
+
test_done
echo "other content" > foo
git rm --cached foo'
-test_expect_failure \
- 'Test that git rm --cached foo fails if the index matches neither the file nor HEAD' \
- 'echo content > foo
+test_expect_success \
+ 'Test that git rm --cached foo fails if the index matches neither the file nor HEAD' '
+ echo content > foo
git add foo
git commit -m foo
echo "other content" > foo
git add foo
echo "yet another content" > foo
- git rm --cached foo'
+ ! git rm --cached foo
+'
test_expect_success \
'Test that git rm --cached -f foo works in case where --cached only did not' \
if test "$test_failed_remove" = y; then
chmod a-w .
-test_expect_failure \
+test_expect_success \
'Test that "git rm -f" fails if its rm fails' \
- 'git rm -f baz'
+ '! git rm -f baz'
chmod 775 .
else
test_expect_success 'skipping removal failure (perhaps running as root?)' :
! test -d frotz
'
-test_expect_failure 'Remove nonexistent file returns nonzero exit status' '
- git rm nonexistent
+test_expect_success 'Remove nonexistent file returns nonzero exit status' '
+ ! git rm nonexistent
'
test_done
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2008 Timo Hirvonen
+#
+
+test_description='Test diff/status color escape codes'
+. ./test-lib.sh
+
+color()
+{
+ git config diff.color.new "$1" &&
+ test "`git config --get-color diff.color.new`" = "\e$2"
+}
+
+invalid_color()
+{
+ git config diff.color.new "$1" &&
+ test -z "`git config --get-color diff.color.new 2>/dev/null`"
+}
+
+test_expect_success 'reset' '
+ color "reset" "[m"
+'
+
+test_expect_success 'attribute before color name' '
+ color "bold red" "[1;31m"
+'
+
+test_expect_success 'color name before attribute' '
+ color "red bold" "[1;31m"
+'
+
+test_expect_success 'attr fg bg' '
+ color "ul blue red" "[4;34;41m"
+'
+
+test_expect_success 'fg attr bg' '
+ color "blue ul red" "[4;34;41m"
+'
+
+test_expect_success 'fg bg attr' '
+ color "blue red ul" "[4;34;41m"
+'
+
+test_expect_success '256 colors' '
+ color "254 bold 255" "[1;38;5;254;48;5;255m"
+'
+
+test_expect_success 'color too small' '
+ invalid_color "-2"
+'
+
+test_expect_success 'color too big' '
+ invalid_color "256"
+'
+
+test_expect_success 'extra character after color number' '
+ invalid_color "3X"
+'
+
+test_expect_success 'extra character after color name' '
+ invalid_color "redX"
+'
+
+test_expect_success 'extra character after attribute' '
+ invalid_color "dimX"
+'
+
+test_done
'git-checkout master
git apply --stat --summary C.diff'
-test_expect_failure 'check binary diff -- should fail.' \
- 'git-checkout master
- git apply --check B.diff'
-
-test_expect_failure 'check binary diff (copy) -- should fail.' \
- 'git-checkout master
- git apply --check C.diff'
-
-test_expect_failure 'check incomplete binary diff with replacement -- should fail.' \
- 'git-checkout master
- git apply --check --allow-binary-replacement B.diff'
+test_expect_success 'check binary diff -- should fail.' \
+ 'git-checkout master &&
+ ! git apply --check B.diff'
+
+test_expect_success 'check binary diff (copy) -- should fail.' \
+ 'git-checkout master &&
+ ! git apply --check C.diff'
+
+test_expect_success \
+ 'check incomplete binary diff with replacement -- should fail.' '
+ git-checkout master &&
+ ! git apply --check --allow-binary-replacement B.diff
+'
-test_expect_failure 'check incomplete binary diff with replacement (copy) -- should fail.' \
- 'git-checkout master
- git apply --check --allow-binary-replacement C.diff'
+test_expect_success \
+ 'check incomplete binary diff with replacement (copy) -- should fail.' '
+ git-checkout master &&
+ ! git apply --check --allow-binary-replacement C.diff
+'
test_expect_success 'check binary diff with replacement.' \
'git-checkout master
# Now we start applying them.
do_reset () {
- rm -f file?
- git-reset --hard
+ rm -f file? &&
+ git-reset --hard &&
git-checkout -f master
}
-test_expect_failure 'apply binary diff -- should fail.' \
- 'do_reset
- git apply B.diff'
+test_expect_success 'apply binary diff -- should fail.' \
+ 'do_reset &&
+ ! git apply B.diff'
-test_expect_failure 'apply binary diff -- should fail.' \
- 'do_reset
- git apply --index B.diff'
+test_expect_success 'apply binary diff -- should fail.' \
+ 'do_reset &&
+ ! git apply --index B.diff'
-test_expect_failure 'apply binary diff (copy) -- should fail.' \
- 'do_reset
- git apply C.diff'
+test_expect_success 'apply binary diff (copy) -- should fail.' \
+ 'do_reset &&
+ ! git apply C.diff'
-test_expect_failure 'apply binary diff (copy) -- should fail.' \
- 'do_reset
- git apply --index C.diff'
+test_expect_success 'apply binary diff (copy) -- should fail.' \
+ 'do_reset &&
+ ! git apply --index C.diff'
test_expect_success 'apply binary diff without replacement.' \
- 'do_reset
+ 'do_reset &&
git apply BF.diff'
test_expect_success 'apply binary diff without replacement (copy).' \
- 'do_reset
+ 'do_reset &&
git apply CF.diff'
test_expect_success 'apply binary diff.' \
- 'do_reset
+ 'do_reset &&
git apply --allow-binary-replacement --index BF.diff &&
test -z "$(git diff --name-status binary)"'
test_expect_success 'apply binary diff (copy).' \
- 'do_reset
+ 'do_reset &&
git apply --allow-binary-replacement --index CF.diff &&
test -z "$(git diff --name-status binary)"'
# test
-test_expect_failure 'apply at the end' \
- 'git apply --index test-patch'
+test_expect_success 'apply at the end' \
+ '! git apply --index test-patch'
cat >test-patch <<\EOF
diff a/file b/file
c'
git update-index file
-test_expect_failure 'apply at the beginning' \
- 'git apply --index test-patch'
+test_expect_success 'apply at the beginning' \
+ '! git apply --index test-patch'
test_done
cp -f .git/objects/9d/235ed07cd19811a6ceb342de82f190e49c9f68 \
.git/objects/c8/2de19312b6c3695c0c18f70709a6c535682a67'
-test_expect_failure \
+test_expect_success \
'make sure index-pack detects the SHA1 collision' \
- 'git-index-pack -o bad.idx test-3.pack'
+ '! git-index-pack -o bad.idx test-3.pack'
+
+test_expect_success \
+ 'honor pack.packSizeLimit' \
+ 'git config pack.packSizeLimit 200 &&
+ packname_4=$(git pack-objects test-4 <obj-list) &&
+ test 3 = $(ls test-4-*.pack | wc -l)'
test_done
'both packs should be identical' \
'cmp "test-1-${pack1}.pack" "test-2-${pack2}.pack"'
-test_expect_failure \
+test_expect_success \
'index v1 and index v2 should be different' \
- 'cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx"'
+ '! cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx"'
test_expect_success \
'index-pack with index version 1' \
'git verify-pack -v "test-3-${pack3}.pack"'
test "$have_64bits" &&
-test_expect_failure \
+test_expect_success \
'64-bit offsets: should be different from previous index v2 results' \
- 'cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"'
+ '! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"'
test "$have_64bits" &&
test_expect_success \
bs=1 count=20 conv=notrunc &&
git cat-file blob "$delta_sha1" > blob_2 )'
-test_expect_failure \
+test_expect_success \
'[index v1] 3) corrupted delta happily returned wrong data' \
- 'cmp blob_1 blob_2'
+ '! cmp blob_1 blob_2'
-test_expect_failure \
+test_expect_success \
'[index v1] 4) confirm that the pack is actually corrupted' \
- 'git fsck --full $commit'
+ '! git fsck --full $commit'
test_expect_success \
'[index v1] 5) pack-objects happily reuses corrupted data' \
'pack4=$(git pack-objects test-4 <obj-list) &&
test -f "test-4-${pack1}.pack"'
-test_expect_failure \
+test_expect_success \
'[index v1] 6) newly created pack is BAD !' \
- 'git verify-pack -v "test-4-${pack1}.pack"'
+ '! git verify-pack -v "test-4-${pack1}.pack"'
test_expect_success \
'[index v2] 1) stream pack to repository' \
bs=1 count=20 conv=notrunc &&
git cat-file blob "$delta_sha1" > blob_4 )'
-test_expect_failure \
+test_expect_success \
'[index v2] 3) corrupted delta happily returned wrong data' \
- 'cmp blob_3 blob_4'
+ '! cmp blob_3 blob_4'
-test_expect_failure \
+test_expect_success \
'[index v2] 4) confirm that the pack is actually corrupted' \
- 'git fsck --full $commit'
+ '! git fsck --full $commit'
-test_expect_failure \
+test_expect_success \
'[index v2] 5) pack-objects refuses to reuse corrupted data' \
- 'git pack-objects test-5 <obj-list'
+ '! git pack-objects test-5 <obj-list'
test_done
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2008 Johannes E. Schindelin
+#
+
+test_description='prune'
+. ./test-lib.sh
+
+test_expect_success setup '
+
+ : > file &&
+ git add file &&
+ test_tick &&
+ git commit -m initial &&
+ git gc
+
+'
+
+test_expect_success 'prune stale packs' '
+
+ orig_pack=$(echo .git/objects/pack/*.pack) &&
+ : > .git/objects/tmp_1.pack &&
+ : > .git/objects/tmp_2.pack &&
+ test-chmtime -86501 .git/objects/tmp_1.pack &&
+ git prune --expire 1.day &&
+ test -f $orig_pack &&
+ test -f .git/objects/tmp_2.pack &&
+ ! test -f .git/objects/tmp_1.pack
+
+'
+
+test_done
cat >victim/.git/hooks/pre-receive <<'EOF'
#!/bin/sh
-printf "$@" >>$GIT_DIR/pre-receive.args
+printf %s "$@" >>$GIT_DIR/pre-receive.args
cat - >$GIT_DIR/pre-receive.stdin
echo STDOUT pre-receive
echo STDERR pre-receive >&2
cat >victim/.git/hooks/update <<'EOF'
#!/bin/sh
echo "$@" >>$GIT_DIR/update.args
-read x; printf "$x" >$GIT_DIR/update.stdin
+read x; printf %s "$x" >$GIT_DIR/update.stdin
echo STDOUT update $1
echo STDERR update $1 >&2
test "$1" = refs/heads/master || exit
cat >victim/.git/hooks/post-receive <<'EOF'
#!/bin/sh
-printf "$@" >>$GIT_DIR/post-receive.args
+printf %s "$@" >>$GIT_DIR/post-receive.args
cat - >$GIT_DIR/post-receive.stdin
echo STDOUT post-receive
echo STDERR post-receive >&2
cat >victim/.git/hooks/post-update <<'EOF'
#!/bin/sh
echo "$@" >>$GIT_DIR/post-update.args
-read x; printf "$x" >$GIT_DIR/post-update.stdin
+read x; printf %s "$x" >$GIT_DIR/post-update.stdin
echo STDOUT post-update
echo STDERR post-update >&2
EOF
chmod u+x victim/.git/hooks/post-update
-test_expect_failure push '
- git-send-pack --force ./victim/.git master tofail >send.out 2>send.err
+test_expect_success push '
+ ! git-send-pack --force ./victim/.git master tofail >send.out 2>send.err
'
test_expect_success 'updated as expected' '
! test -s victim/.git/post-receive.args
'
-test_expect_failure 'send-pack produced no output' '
- test -s send.out
+test_expect_success 'send-pack produced no output' '
+ ! test -s send.out
'
cat <<EOF >expect
chmod u+x clone${clone}/.git/hooks/post-merge
done
-test_expect_failure 'post-merge does not run for up-to-date ' '
+test_expect_success 'post-merge does not run for up-to-date ' '
GIT_DIR=clone1/.git git merge $commit0 &&
- test -e clone1/.git/post-merge.args
+ ! test -f clone1/.git/post-merge.args
'
test_expect_success 'post-merge runs as expected ' '
test_expect_success "clone shallow object count" \
"test \"count: 18\" = \"$(grep count count.shallow)\""
-test_expect_failure "pull in shallow repo with missing merge base" \
- "(cd shallow; git pull --depth 4 .. A)"
+test_expect_success "pull in shallow repo with missing merge base" \
+ "(cd shallow && ! git pull --depth 4 .. A)"
test_done
'
-test_expect_failure 'fetch must not resolve short tag name' '
+test_expect_success 'fetch must not resolve short tag name' '
cd "$D" &&
cd five &&
git init &&
- git fetch .. anno:five
+ ! git fetch .. anno:five
'
-test_expect_failure 'fetch must not resolve short remote name' '
+test_expect_success 'fetch must not resolve short remote name' '
cd "$D" &&
git-update-ref refs/remotes/six/HEAD HEAD
cd six &&
git init &&
- git fetch .. six:six
+ ! git fetch .. six:six
'
git bundle create bundle2 master~2..master
'
-test_expect_failure 'unbundle 1' '
+test_expect_success 'unbundle 1' '
cd "$D/bundle" &&
git checkout -b some-branch &&
- git fetch "$D/bundle1" master:master
+ ! git fetch "$D/bundle1" master:master
'
test_expect_success 'bundle 1 has only 3 files ' '
git reset --hard before-rebase &&
git config branch.to-rebase.rebase 1 &&
git pull . copy &&
+ git config branch.to-rebase.rebase 0 &&
test $(git rev-parse HEAD^) = $(git rev-parse copy) &&
test new = $(git show HEAD:file2)
'
+test_expect_success '--rebase with rebased upstream' '
+
+ git remote add -f me . &&
+ git checkout copy &&
+ git reset --hard HEAD^ &&
+ echo conflicting modification > file &&
+ git commit -m conflict file &&
+ git checkout to-rebase &&
+ echo file > file2 &&
+ git commit -m to-rebase file2 &&
+ git pull --rebase me copy &&
+ test "conflicting modification" = "$(cat file)" &&
+ test file = $(cat file2)
+
+'
+
test_done
'
-test_expect_failure 'fsck fails' '
-
- git fsck
+test_expect_success 'fsck fails' '
+ ! git fsck
'
test_expect_success 'upload-pack fails due to error in pack-objects' '
'
-test_expect_failure 'fsck fails' '
-
- git fsck
+test_expect_success 'fsck fails' '
+ ! git fsck
'
test_expect_success 'upload-pack fails due to error in rev-list' '
'
-test_expect_failure 'fetch fails' '
+test_expect_success 'fetch fails' '
- git fetch .. master
+ ! git fetch .. master
'
. ./test-lib.sh
-test_expect_failure \
+test_expect_success \
'clone of non-existent source should fail' \
- 'git-clone foo bar'
+ '! git-clone foo bar'
-test_expect_failure \
+test_expect_success \
'failed clone should not leave a directory' \
- 'cd bar'
+ '! test -d bar'
# Need a repo to clone
test_create_repo foo
# source repository given to git-clone should be relative to the
# current path not to the target dir
-test_expect_failure \
+test_expect_success \
'clone of non-existent (relative to $PWD) source should fail' \
- 'git-clone ../foo baz'
+ '! git-clone ../foo baz'
test_expect_success \
'clone should work now that source exists' \
cd "$base_dir"
-test_expect_failure 'creating too deep nesting' \
+test_expect_success 'creating too deep nesting' \
'git clone -l -s C D &&
git clone -l -s D E &&
git clone -l -s E F &&
git clone -l -s F G &&
-git clone -l -s G H &&
-cd H &&
-test_valid_repo'
+git clone -l -s G H'
+
+test_expect_success 'invalidity of deepest repository' \
+'cd H && {
+ test_valid_repo
+ test $? -ne 0
+}'
cd "$base_dir"
cd "$base_dir"
-test_expect_failure 'that info/alternates is necessary' \
+test_expect_success 'that info/alternates is necessary' \
'cd C &&
-rm .git/objects/info/alternates &&
-test_valid_repo'
+rm -f .git/objects/info/alternates &&
+! (test_valid_repo)'
cd "$base_dir"
cd "$base_dir"
-test_expect_failure 'that relative alternate is only possible for current dir' \
-'cd D &&
-test_valid_repo'
+test_expect_success \
+ 'that relative alternate is only possible for current dir' '
+ cd D &&
+ ! (test_valid_repo)
+'
cd "$base_dir"
--- /dev/null
+#!/bin/sh
+
+test_description='properly cull all ancestors'
+
+. ./test-lib.sh
+
+commit () {
+ test_tick &&
+ echo $1 >file &&
+ git commit -a -m $1 &&
+ git tag $1
+}
+
+test_expect_success setup '
+
+ touch file &&
+ git add file &&
+
+ commit one &&
+
+ test_tick=$(($test_tick - 2400))
+
+ commit two &&
+ commit three &&
+ commit four &&
+
+ git log --pretty=oneline --abbrev-commit
+'
+
+test_expect_failure 'one is ancestor of others and should not be shown' '
+
+ git rev-list one --not four >result &&
+ >expect &&
+ diff -u expect result
+
+'
+
+test_done
"git diff test.txt test2.txt"
cp test.txt backup.txt
-test_expect_failure "merge with conflicts" \
- "git merge-file test.txt orig.txt new3.txt"
+test_expect_success "merge with conflicts" \
+ "! git merge-file test.txt orig.txt new3.txt"
cat > expect.txt << EOF
<<<<<<< test.txt
test_expect_success "expected conflict markers" "git diff test.txt expect.txt"
cp backup.txt test.txt
-test_expect_failure "merge with conflicts, using -L" \
- "git merge-file -L 1 -L 2 test.txt orig.txt new3.txt"
+test_expect_success "merge with conflicts, using -L" \
+ "! git merge-file -L 1 -L 2 test.txt orig.txt new3.txt"
cat > expect.txt << EOF
<<<<<<< 1
"git diff test.txt expect.txt"
sed "s/ tu / TU /" < new1.txt > new5.txt
-test_expect_failure "conflict in removed tail" \
- "git merge-file -p orig.txt new1.txt new5.txt > out"
+test_expect_success "conflict in removed tail" \
+ "! git merge-file -p orig.txt new1.txt new5.txt > out"
cat > expect << EOF
Dominus regit me,
GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
'
-test_expect_failure "combined merge conflicts" "git merge -m final G"
+test_expect_success "combined merge conflicts" "! git merge -m final G"
cat > expect << EOF
<<<<<<< HEAD:a1
git add symlink &&
git-commit -m b-file'
-test_expect_failure \
+test_expect_success \
'merge master into b-symlink, which has a different symbolic link' '
-! git-checkout b-symlink ||
-git-merge master'
+git-checkout b-symlink &&
+! git-merge master'
test_expect_success \
'the merge result must be a file' '
test -f symlink'
-test_expect_failure \
+test_expect_success \
'merge master into b-file, which has a file instead of a symbolic link' '
-! (git-reset --hard &&
-git-checkout b-file) ||
-git-merge master'
+git-reset --hard && git-checkout b-file &&
+! git-merge master'
test_expect_success \
'the merge result must be a file' '
test -f symlink'
-test_expect_failure \
+test_expect_success \
'merge b-file, which has a file instead of a symbolic link, into master' '
-! (git-reset --hard &&
-git-checkout master) ||
-git-merge b-file'
+git-reset --hard &&
+git-checkout master &&
+! git-merge b-file'
test_expect_success \
'the merge result must be a file' '
grep "$HASH6 is first bad commit" my_bisect_log.txt
'
+test_expect_success 'bisect starting with a detached HEAD' '
+
+ git bisect reset &&
+ git checkout master^ &&
+ HEAD=$(git rev-parse --verify HEAD) &&
+ git bisect start &&
+ test $HEAD = $(cat .git/head-name) &&
+ git bisect reset &&
+ test $HEAD = $(git rev-parse --verify HEAD)
+
+'
+
#
#
test_done
test_expect_success 'final^1^2' "test $(git rev-parse start2) = $(git rev-parse final^1^2)"
test_expect_success 'final^1^2 != final^1^1' "test $(git rev-parse final^1^2) != $(git rev-parse final^1^1)"
test_expect_success 'final^1^3 not valid' "if git rev-parse --verify final^1^3; then false; else :; fi"
-test_expect_failure '--verify start2^1' 'git rev-parse --verify start2^1'
+test_expect_success '--verify start2^1' '! git rev-parse --verify start2^1'
test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0'
test_expect_success 'repack for next test' 'git repack -a -d'
test -z "$bad"
'
-test_expect_failure 'Check invalid atoms names are errors' '
- git-for-each-ref --format="%(INVALID)" refs/heads
+test_expect_success 'Check invalid atoms names are errors' '
+ ! git-for-each-ref --format="%(INVALID)" refs/heads
'
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
git-for-each-ref --format="%(authordate:rfc2822)" refs/heads
'
-test_expect_failure 'Check invalid format specifiers are errors' '
- git-for-each-ref --format="%(authordate:INVALID)" refs/heads
+test_expect_success 'Check invalid format specifiers are errors' '
+ ! git-for-each-ref --format="%(authordate:INVALID)" refs/heads
'
cat >expected <<\EOF
git diff-tree -r -M --name-status HEAD^ HEAD | \
grep "^R100..*path2/README..*path1/path2/README"'
-test_expect_failure \
+test_expect_success \
'do not move directory over existing directory' \
- 'mkdir path0 && mkdir path0/path2 && git mv path2 path0'
+ 'mkdir path0 && mkdir path0/path2 && ! git mv path2 path0'
test_expect_success \
'move into "."' \
diff expected actual
'
- test_expect_failure "grep -c $L (no /dev/null)" '
- git grep -c test $H | grep -q "/dev/null"
+ test_expect_success "grep -c $L (no /dev/null)" '
+ ! git grep -c test $H | grep -q /dev/null
'
done
test `git-tag | wc -l` -eq 0
'
-test_expect_failure 'looking for a tag in an empty tree should fail' \
- 'tag_exists mytag'
+test_expect_success '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 &&
# special cases for creating tags:
-test_expect_failure \
+test_expect_success \
'trying to create a tag with the name of one existing should fail' \
- 'git tag mytag'
+ '! git tag mytag'
test_expect_success \
'trying to create a tag with a non-valid name should fail' '
! tag_exists myhead
'
-test_expect_failure 'trying to delete an already deleted tag should fail' \
- 'git-tag -d mytag'
+test_expect_success 'trying to delete an already deleted tag should fail' \
+ '! git-tag -d mytag'
# listing various tags with pattern matching:
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_success 'trying to verify an unknown tag should fail' \
+ '! git-tag -v unknown-tag'
-test_expect_failure \
+test_expect_success \
'trying to verify a non-annotated and non-signed tag should fail' \
- 'git-tag -v non-annotated-tag'
+ '! git-tag -v non-annotated-tag'
-test_expect_failure \
+test_expect_success \
'trying to verify many non-annotated or unknown tags, should fail' \
- 'git-tag -v unknown-tag1 non-annotated-tag unknown-tag2'
+ '! git-tag -v unknown-tag1 non-annotated-tag unknown-tag2'
# creating annotated tags:
# try to sign with bad user.signingkey
git config user.signingkey BobTheMouse
-test_expect_failure \
+test_expect_success \
'git-tag -s fails if gpg is misconfigured' \
- 'git tag -s -m tail tag-gpg-failure'
+ '! git tag -s -m tail tag-gpg-failure'
git config --unset user.signingkey
# try to verify without gpg:
rm -rf gpghome
-test_expect_failure \
+test_expect_success \
'verify signed tag fails when public key is not present' \
- 'git-tag -v signed-tag'
+ '! git-tag -v signed-tag'
-test_expect_failure \
+test_expect_success \
'git-tag -a fails if tag annotation is empty' '
- GIT_EDITOR=cat git tag -a initial-comment
+ ! (GIT_EDITOR=cat git tag -a initial-comment)
'
test_expect_success \
'test -d path0 &&
test -f path0/COPYING'
-test_expect_failure \
+test_expect_success \
'checking lack of path1/path2/COPYING' \
- 'test -f path1/path2/COPYING'
+ '! test -f path1/path2/COPYING'
-test_expect_failure \
+test_expect_success \
'checking lack of path1/COPYING' \
- 'test -f path1/COPYING'
+ '! test -f path1/COPYING'
-test_expect_failure \
+test_expect_success \
'checking lack of COPYING' \
- 'test -f COPYING'
+ '! test -f COPYING'
-test_expect_failure \
+test_expect_success \
'checking checking lack of path1/COPYING-TOO' \
- 'test -f path0/COPYING-TOO'
+ '! test -f path0/COPYING-TOO'
-test_expect_failure \
+test_expect_success \
'checking lack of path1/path2' \
- 'test -d path1/path2'
+ '! test -d path1/path2'
-test_expect_failure \
+test_expect_success \
'checking lack of path1' \
- 'test -d path1'
+ '! test -d path1'
test_done
fi
'
+test_expect_success 'checkout to detach HEAD with :/message' '
+
+ git checkout -f master && git clean -f &&
+ git checkout ":/Initial" &&
+ H=$(git rev-parse --verify HEAD) &&
+ M=$(git show-ref -s --verify refs/heads/master) &&
+ test "z$H" = "z$M" &&
+ if git symbolic-ref HEAD >/dev/null 2>&1
+ then
+ echo "OOPS, HEAD is still symbolic???"
+ false
+ else
+ : happy
+ fi
+'
+
test_expect_success 'checkout to detach HEAD with HEAD^0' '
git checkout -f master && git clean -f &&
#
# Test setup:
-# -create a repository in directory lib
+# -create a repository in directory init
# -add a couple of files
-# -add directory lib to 'superproject', this creates a DIRLINK entry
+# -add directory init to 'superproject', this creates a DIRLINK entry
# -add a couple of regular files to enable testing of submodule filtering
-# -mv lib subrepo
+# -mv init subrepo
# -add an entry to .gitmodules for submodule 'example'
#
test_expect_success 'Prepare submodule testing' '
git-add t &&
git-commit -m "initial commit" &&
git branch initial HEAD &&
- mkdir lib &&
- cd lib &&
+ mkdir init &&
+ cd init &&
git init &&
echo a >a &&
git add a &&
cd .. &&
echo a >a &&
echo z >z &&
- git add a lib z &&
+ git add a init z &&
git-commit -m "super commit 1" &&
- mv lib .subrepo &&
- GIT_CONFIG=.gitmodules git config submodule.example.url git://example.com/lib.git
+ mv init .subrepo &&
+ GIT_CONFIG=.gitmodules git config submodule.example.url git://example.com/init.git
'
test_expect_success 'status should fail for unmapped paths' '
then
echo "[OOPS] submodule status succeeded"
false
- elif ! GIT_CONFIG=.gitmodules git config submodule.example.path lib
+ elif ! GIT_CONFIG=.gitmodules git config submodule.example.path init
then
echo "[OOPS] git config failed to update .gitmodules"
false
test_expect_success 'init should register submodule url in .git/config' '
git-submodule init &&
url=$(git config submodule.example.url) &&
- if test "$url" != "git://example.com/lib.git"
+ if test "$url" != "git://example.com/init.git"
then
echo "[OOPS] init succeeded but submodule url is wrong"
false
'
test_expect_success 'update should fail when path is used by a file' '
- echo "hello" >lib &&
+ echo "hello" >init &&
if git-submodule update
then
echo "[OOPS] update should have failed"
false
- elif test "$(cat lib)" != "hello"
+ elif test "$(cat init)" != "hello"
then
- echo "[OOPS] update failed but lib file was molested"
+ echo "[OOPS] update failed but init file was molested"
false
else
- rm lib
+ rm init
fi
'
test_expect_success 'update should fail when path is used by a nonempty directory' '
- mkdir lib &&
- echo "hello" >lib/a &&
+ mkdir init &&
+ echo "hello" >init/a &&
if git-submodule update
then
echo "[OOPS] update should have failed"
false
- elif test "$(cat lib/a)" != "hello"
+ elif test "$(cat init/a)" != "hello"
then
- echo "[OOPS] update failed but lib/a was molested"
+ echo "[OOPS] update failed but init/a was molested"
false
else
- rm lib/a
+ rm init/a
fi
'
test_expect_success 'update should work when path is an empty dir' '
- rm -rf lib &&
- mkdir lib &&
+ rm -rf init &&
+ mkdir init &&
git-submodule update &&
- head=$(cd lib && git rev-parse HEAD) &&
+ head=$(cd init && git rev-parse HEAD) &&
if test -z "$head"
then
echo "[OOPS] Failed to obtain submodule head"
'
test_expect_success 'status should be "modified" after submodule commit' '
- cd lib &&
+ cd init &&
echo b >b &&
git add b &&
git-commit -m "submodule commit 2" &&
'
test_expect_success 'update should checkout rev1' '
- git-submodule update &&
- head=$(cd lib && git rev-parse HEAD) &&
+ git-submodule update init &&
+ head=$(cd init && git rev-parse HEAD) &&
if test -z "$head"
then
echo "[OOPS] submodule git rev-parse returned nothing"
test_expect_success 'apply submodule diff' '
git branch second &&
(
- cd lib &&
+ cd init &&
echo s >s &&
git add s &&
git commit -m "change subproject"
) &&
- git update-index --add lib &&
- git-commit -m "change lib" &&
+ git update-index --add init &&
+ git-commit -m "change init" &&
git-format-patch -1 --stdout >P.diff &&
git checkout second &&
git apply --index P.diff &&
git-add file && \
git-status | grep 'Initial commit'"
-test_expect_failure \
+test_expect_success \
"fail initial amend" \
- "git-commit --amend"
+ "! git-commit --amend"
test_expect_success \
"initial commit" \
"git-commit -m initial"
-test_expect_failure \
+test_expect_success \
"invalid options 1" \
- "git-commit -m foo -m bar -F file"
+ "! git-commit -m foo -m bar -F file"
-test_expect_failure \
+test_expect_success \
"invalid options 2" \
- "git-commit -C HEAD -m illegal"
+ "! git-commit -C HEAD -m illegal"
-test_expect_failure \
+test_expect_success \
"using paths with -a" \
"echo King of the bongo >file &&
- git-commit -m foo -a file"
+ ! git-commit -m foo -a file"
-test_expect_failure \
+test_expect_success \
"using paths with --interactive" \
"echo bong-o-bong >file &&
- echo 7 | git-commit -m foo --interactive file"
+ ! echo 7 | git-commit -m foo --interactive file"
-test_expect_failure \
+test_expect_success \
"using invalid commit with -C" \
- "git-commit -C bogus"
+ "! git-commit -C bogus"
-test_expect_failure \
+test_expect_success \
"testing nothing to commit" \
- "git-commit -m initial"
+ "! git-commit -m initial"
test_expect_success \
"next commit" \
"echo 'bongo bongo bongo' >file \
git-commit -m next -a"
-test_expect_failure \
+test_expect_success \
"commit message from non-existing file" \
"echo 'more bongo: bongo bongo bongo bongo' >file && \
- git-commit -F gah -a"
+ ! git-commit -F gah -a"
# Empty except stray tabs and spaces on a few lines.
sed -e 's/@$//' >msg <<EOF
@
Signed-off-by: hula
EOF
-test_expect_failure \
+test_expect_success \
"empty commit message" \
- "git-commit -F msg -a"
+ "! git-commit -F msg -a"
test_expect_success \
"commit message from file" \
"amend commit" \
"VISUAL=./editor git-commit --amend"
-test_expect_failure \
+test_expect_success \
"passing -m and -F" \
"echo 'enough with the bongos' >file && \
- git-commit -F msg -m amending ."
+ ! git-commit -F msg -m amending ."
test_expect_success \
"using message from other commit" \
'
+test_expect_success 'amend using the message from a commit named with tag' '
+
+ git reset --hard &&
+ test_tick &&
+ git commit --allow-empty -m "old commit" &&
+ old=$(git rev-parse --verify HEAD) &&
+ git tag -a -m "tag on old" tagged-old HEAD &&
+ test_tick &&
+ git commit --allow-empty -m "new commit" &&
+ new=$(git rev-parse --verify HEAD) &&
+ test_tick &&
+ git commit --allow-empty --amend -C tagged-old &&
+ git show --pretty="format:%ad %s" "$old" >expected &&
+ git show --pretty="format:%ad %s" HEAD >actual &&
+ diff -u expected actual
+
+'
+
test_done
exit 1
EOF
-test_expect_failure 'with failing hook' '
+test_expect_success 'with failing hook' '
echo "another" >> file &&
git add file &&
- git commit -m "another"
+ ! git commit -m "another"
'
exit 1
EOF
-test_expect_failure 'with failing hook' '
+test_expect_success 'with failing hook' '
echo "another" >> file &&
git add file &&
- git commit -m "another"
+ ! git commit -m "another"
'
-test_expect_failure 'with failing hook (editor)' '
+test_expect_success 'with failing hook (editor)' '
echo "more another" >> file &&
git add file &&
echo "more another" > FAKE_MSG &&
- GIT_EDITOR="$FAKE_EDITOR" git commit
+ ! (GIT_EDITOR="$FAKE_EDITOR" git commit)
'
'prepare reference tree' \
'echo "1A quick brown fox jumps over the" >file &&
echo "lazy dog" >>file &&
- git add file
+ git add file &&
GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
test_expect_success \
echo " echo \"!\$a!\""
echo "done >commandline"
echo "cat > msgtxt"
- ) >fake.sendmail
- chmod +x ./fake.sendmail
- git add fake.sendmail
+ ) >fake.sendmail &&
+ chmod +x ./fake.sendmail &&
+ git add fake.sendmail &&
GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
test_expect_success 'Extract patches' '
name='detect node change from file to directory #1'
-test_expect_failure "$name" "
+test_expect_success "$name" "
mkdir dir/new_file &&
mv dir/file dir/new_file/file &&
mv dir/new_file dir/file &&
git update-index --remove dir/file &&
git update-index --add dir/file/file &&
- git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
+ git commit -m '$name' &&
+ ! git-svn set-tree --find-copies-harder --rmdir \
remotes/git-svn..mybranch" || true
name='detect node change from directory to file #1'
-test_expect_failure "$name" "
+test_expect_success "$name" "
rm -rf dir '$GIT_DIR'/index &&
git checkout -f -b mybranch2 remotes/git-svn &&
mv bar/zzz zzz &&
git update-index --remove -- bar/zzz &&
git update-index --add -- bar &&
git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
+ ! git-svn set-tree --find-copies-harder --rmdir \
remotes/git-svn..mybranch2" || true
name='detect node change from file to directory #2'
-test_expect_failure "$name" "
+test_expect_success "$name" "
rm -f '$GIT_DIR'/index &&
git checkout -f -b mybranch3 remotes/git-svn &&
rm bar/zzz &&
echo yyy > bar/zzz/yyy &&
git update-index --add bar/zzz/yyy &&
git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
+ ! git-svn set-tree --find-copies-harder --rmdir \
remotes/git-svn..mybranch3" || true
name='detect node change from directory to file #2'
-test_expect_failure "$name" "
+test_expect_success "$name" "
rm -f '$GIT_DIR'/index &&
git checkout -f -b mybranch4 remotes/git-svn &&
rm -rf dir &&
echo asdf > dir &&
git update-index --add -- dir &&
git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
+ ! git-svn set-tree --find-copies-harder --rmdir \
remotes/git-svn..mybranch4" || true
test_expect_success "$name" "git diff a expected"
-test_expect_failure 'exit if remote refs are ambigious' "
+test_expect_success 'exit if remote refs are ambigious' "
git config --add svn-remote.svn.fetch \
bar:refs/remotes/git-svn &&
- git-svn migrate
- "
+ ! git-svn migrate
+"
-test_expect_failure 'exit if init-ing a would clobber a URL' "
+test_expect_success 'exit if init-ing a would clobber a URL' "
svnadmin create ${PWD}/svnrepo2 &&
svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
git config --unset svn-remote.svn.fetch \
'^bar:refs/remotes/git-svn$' &&
- git-svn init ${svnrepo}2/bar
+ ! git-svn init ${svnrepo}2/bar
"
test_expect_success \
rm -rf t.svn
"
-test_expect_failure 'commit conflicting change from git' "
+test_expect_success 'commit conflicting change from git' "
echo second line from git >> file &&
git commit -a -m 'second line from git' &&
- git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
- " || true
+ ! git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+"
test_expect_success 'commit complementing change from git' "
git reset --hard HEAD~1 &&
git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
"
-test_expect_failure 'dcommit fails to commit because of conflict' "
+test_expect_success 'dcommit fails to commit because of conflict' "
git-svn init $svnrepo &&
git-svn fetch &&
git reset --hard refs/remotes/git-svn &&
rm -rf t.svn &&
echo 'fourth line from git' >> file &&
git commit -a -m 'fourth line from git' &&
- git-svn dcommit
- " || true
+ ! git-svn dcommit
+ "
test_expect_success 'dcommit does the svn equivalent of an index merge' "
git reset --hard refs/remotes/git-svn &&
rm -rf t.svn
"
-test_expect_failure 'multiple dcommit from git-svn will not clobber svn' "
+test_expect_success 'multiple dcommit from git-svn will not clobber svn' "
git reset --hard refs/remotes/git-svn &&
echo new file >> new-file &&
git update-index --add new-file &&
git commit -a -m 'new file' &&
echo clobber > file &&
git commit -a -m 'clobber' &&
- git svn dcommit
- " || true
+ ! git svn dcommit
+ "
test_expect_success 'check that rebase really failed' 'test -d .dotest'
test x\"\`sed -n -e 61p < file\`\" = x6611
"
-test_expect_failure 'attempt to dcommit with a dirty index' '
+test_expect_success 'attempt to dcommit with a dirty index' '
echo foo >>file &&
git add file &&
- git svn dcommit
+ ! git svn dcommit
'
test_done
M 755 0000000000000000000000000000000000000001 zero1
INPUT_END
-test_expect_failure \
- 'B: fail on invalid blob sha1' \
- 'git-fast-import <input'
+test_expect_success 'B: fail on invalid blob sha1' '
+ ! git-fast-import <input
+'
rm -f .git/objects/pack_* .git/objects/index_*
cat >input <<INPUT_END
from refs/heads/master
INPUT_END
-test_expect_failure \
- 'B: fail on invalid branch name ".badbranchname"' \
- 'git-fast-import <input'
+test_expect_success 'B: fail on invalid branch name ".badbranchname"' '
+ ! git-fast-import <input
+'
rm -f .git/objects/pack_* .git/objects/index_*
cat >input <<INPUT_END
from refs/heads/master
INPUT_END
-test_expect_failure \
- 'B: fail on invalid branch name "bad[branch]name"' \
- 'git-fast-import <input'
+test_expect_success 'B: fail on invalid branch name "bad[branch]name"' '
+ ! git-fast-import <input
+'
rm -f .git/objects/pack_* .git/objects/index_*
cat >input <<INPUT_END
from refs/heads/branch^0
INPUT_END
-test_expect_failure \
- 'E: rfc2822 date, --date-format=raw' \
- 'git-fast-import --date-format=raw <input'
+test_expect_success 'E: rfc2822 date, --date-format=raw' '
+ ! git-fast-import --date-format=raw <input
+'
test_expect_success \
'E: rfc2822 date, --date-format=rfc2822' \
'git-fast-import --date-format=rfc2822 <input'
export CVSROOT CVS_SERVER
rm -rf "$CVSWORK" "$SERVERDIR"
-echo >empty &&
+test_expect_success 'setup' '
+ echo >empty &&
git add empty &&
git commit -q -m "First Commit" &&
+ mkdir secondroot &&
+ ( cd secondroot &&
+ git init &&
+ touch secondrootfile &&
+ git add secondrootfile &&
+ git commit -m "second root") &&
+ git pull secondroot master &&
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 gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
- exit 1
+ GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log"
+'
# note that cvs doesn't accept absolute pathnames
# as argument to co -d
test_expect_success 'basic checkout' \
'GIT_CONFIG="$git_config" cvs -Q co -d cvswork master &&
- test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5))" = "empty/1.1/"'
+ test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/"
+ test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | tail -n 1))" = "secondrootfile/1.1/"'
#------------------------
# PSERVER AUTHENTICATION
'cat request-anonymous | git-cvsserver --strict-paths pserver $SERVERDIR >log 2>&1 &&
tail -n1 log | grep -q "^I LOVE YOU$"'
-test_expect_failure 'req_Root failure (strict-paths)' \
- 'cat request-anonymous | git-cvsserver --strict-paths pserver $WORKDIR >log 2>&1'
+test_expect_success 'req_Root failure (strict-paths)' '
+ ! cat request-anonymous |
+ git-cvsserver --strict-paths pserver $WORKDIR >log 2>&1
+'
test_expect_success 'req_Root (w/o strict-paths)' \
'cat request-anonymous | git-cvsserver pserver $WORKDIR/ >log 2>&1 &&
tail -n1 log | grep -q "^I LOVE YOU$"'
-test_expect_failure 'req_Root failure (w/o strict-paths)' \
- 'cat request-anonymous | git-cvsserver pserver $WORKDIR/gitcvs >log 2>&1'
+test_expect_success 'req_Root failure (w/o strict-paths)' '
+ ! cat request-anonymous |
+ git-cvsserver pserver $WORKDIR/gitcvs >log 2>&1
+'
cat >request-base <<EOF
BEGIN AUTH REQUEST
'cat request-base | git-cvsserver --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
tail -n1 log | grep -q "^I LOVE YOU$"'
-test_expect_failure 'req_Root failure (base-path)' \
- 'cat request-anonymous | git-cvsserver --strict-paths --base-path $WORKDIR pserver $SERVERDIR >log 2>&1'
+test_expect_success 'req_Root failure (base-path)' '
+ ! cat request-anonymous |
+ git-cvsserver --strict-paths --base-path $WORKDIR pserver $SERVERDIR >log 2>&1
+'
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1
'cat request-anonymous | git-cvsserver --export-all pserver $WORKDIR >log 2>&1 &&
tail -n1 log | grep -q "^I LOVE YOU$"'
-test_expect_failure 'req_Root failure (export-all w/o whitelist)' \
- 'cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 ||
- false'
+test_expect_success 'req_Root failure (export-all w/o whitelist)' \
+ '! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)'
test_expect_success 'req_Root (everything together)' \
'cat request-base | git-cvsserver --export-all --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
cd "$WORKDIR"
#TODO: cvsserver doesn't support update w/o -d
-test_expect_failure "cvs update w/o -d doesn't create subdir (TODO)" \
- 'mkdir test &&
+test_expect_failure "cvs update w/o -d doesn't create subdir (TODO)" '
+ mkdir test &&
echo >test/empty &&
git add test &&
git commit -q -m "Single Subdirectory" &&
git push gitcvs.git >/dev/null &&
cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update &&
- test ! -d test'
+ test ! -d test
+'
cd "$WORKDIR"
test_expect_success 'cvs update (subdirectories)' \
test_failure=0
test_count=0
+test_fixed=0
+test_broken=0
trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit
test "$immediate" = "" || { trap - exit; exit 1; }
}
+test_known_broken_ok_ () {
+ test_count=$(expr "$test_count" + 1)
+ test_fixed=$(($test_fixed+1))
+ say_color "" " FIXED $test_count: $@"
+}
+
+test_known_broken_failure_ () {
+ test_count=$(expr "$test_count" + 1)
+ test_broken=$(($test_broken+1))
+ say_color skip " still broken $test_count: $@"
+}
test_debug () {
test "$debug" = "" || eval "$1"
error "bug in the test script: not 2 parameters to test-expect-failure"
if ! test_skip "$@"
then
- say >&3 "expecting failure: $2"
+ say >&3 "checking known breakage: $2"
test_run_ "$2"
- if [ "$?" = 0 -a "$eval_ret" != 0 -a "$eval_ret" -lt 129 ]
+ if [ "$?" = 0 -a "$eval_ret" = 0 ]
then
- test_ok_ "$1"
+ test_known_broken_ok_ "$1"
else
- test_failure_ "$@"
+ test_known_broken_failure_ "$1"
fi
fi
echo >&3 ""
echo >&3 ""
}
-# Most tests can use the created repository, but some amy need to create more.
+# Most tests can use the created repository, but some may need to create more.
# Usage: test_create_repo <directory>
test_create_repo () {
test "$#" = 1 ||
test_done () {
trap - exit
+
+ if test "$test_fixed" != 0
+ then
+ say_color pass "fixed $test_fixed known breakage(s)"
+ fi
+ if test "$test_broken" != 0
+ then
+ say_color error "still have $test_broken known breakage(s)"
+ msg="remaining $(($test_count-$test_broken)) test(s)"
+ else
+ msg="$test_count test(s)"
+ fi
case "$test_failure" in
0)
# We could:
# The Makefile provided will clean this test area so
# we will leave things as they are.
- say_color pass "passed all $test_count test(s)"
+ say_color pass "passed all $msg"
exit 0 ;;
*)
- say_color error "failed $test_failure among $test_count test(s)"
+ say_color error "failed $test_failure among $msg"
exit 1 ;;
esac
OPT_STRING('s', "string", &string, "string", "get a string"),
OPT_STRING(0, "string2", &string, "str", "get another string"),
OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
+ OPT_STRING('o', NULL, &string, "str", "get another string"),
OPT_END(),
};
int i;
struct ref *ref = NULL;
struct ref *last_ref = NULL;
+ if (!transport->data)
+ transport->data = get_http_walker(transport->url);
+
refs_url = xmalloc(strlen(transport->url) + 11);
sprintf(refs_url, "%s/info/refs", transport->url);
- http_init();
-
slot = get_active_slot();
slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
return NULL;
}
- http_cleanup();
-
data = buffer.buf;
start = NULL;
mid = data;
}
if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
int slot = parse_status_slot(k, 13);
+ if (!v)
+ return config_error_nonbool(k);
color_parse(v, k, wt_status_colors[slot]);
return 0;
}