mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'v1.5.3-rc4'
This commit is contained in:
@@ -120,6 +120,7 @@ clean:
|
||||
mv $@+ $@
|
||||
|
||||
%.1 %.5 %.7 : %.xml
|
||||
$(RM) $@
|
||||
xmlto -m callouts.xsl man $<
|
||||
|
||||
%.xml : %.txt
|
||||
|
||||
@@ -40,16 +40,22 @@ Updates since v1.5.2
|
||||
$GIT_DIR to work in a subdirectory of a working tree that is
|
||||
not located at "$GIT_DIR/..".
|
||||
|
||||
- Giving "--file=<file>" option to "git config" is the same as
|
||||
running the command with GIT_CONFIG=<file> environment.
|
||||
|
||||
- "git log" learned a new option "--follow", to follow
|
||||
renaming history of a single file.
|
||||
|
||||
- "git-filter-branch" lets you rewrite the revision history of
|
||||
the current branch, creating a new branch. You can specify a
|
||||
number of filters to modify the commits, files and trees.
|
||||
specified branches. You can specify a number of filters to
|
||||
modify the commits, files and trees.
|
||||
|
||||
- "git-cvsserver" learned new options (--base-path, --export-all,
|
||||
--strict-paths) inspired by git-daemon.
|
||||
|
||||
- "git daemon --base-path-relaxed" can help migrating a repository URL
|
||||
that did not use to use --base-path to use --base-path.
|
||||
|
||||
- "git-commit" can use "-t templatefile" option and commit.template
|
||||
configuration variable to prime the commit message given to you in the
|
||||
editor.
|
||||
@@ -120,6 +126,9 @@ Updates since v1.5.2
|
||||
of the format ('tgz', 'tbz2' or 'zip'). Please update the
|
||||
your configuration file accordingly.
|
||||
|
||||
- "git diff" (but not the plumbing level "git diff-tree") now
|
||||
recursively descends into trees by default.
|
||||
|
||||
- The editor to use with many interactive commands can be
|
||||
overridden with GIT_EDITOR environment variable, or if it
|
||||
does not exist, with core.editor configuration variable. As
|
||||
@@ -165,6 +174,9 @@ Updates since v1.5.2
|
||||
- The diffstat given after a merge (or a pull) honors the
|
||||
color.diff configuration.
|
||||
|
||||
- "git commit --amend" is now compatible with various message source
|
||||
options such as -m/-C/-c/-F.
|
||||
|
||||
- "git-apply --whitespace=strip" removes blank lines added at
|
||||
the end of the file.
|
||||
|
||||
@@ -262,6 +274,6 @@ this release, unless otherwise noted.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.3-rc3
|
||||
O=v1.5.3-rc4
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -101,7 +101,7 @@ Example
|
||||
|
||||
# Proxy settings
|
||||
[core]
|
||||
gitProxy="ssh" for "ssh://kernel.org/"
|
||||
gitProxy="ssh" for "kernel.org"
|
||||
gitProxy=default-proxy ; for the rest
|
||||
|
||||
Variables
|
||||
|
||||
@@ -134,8 +134,8 @@ $ git branch -d -r origin/todo origin/html origin/man <1>
|
||||
$ git branch -D test <2>
|
||||
------------
|
||||
+
|
||||
<1> delete remote-tracking branches "todo", "html", "man"
|
||||
<2> delete "test" branch even if the "master" branch does not have all
|
||||
<1> Delete remote-tracking branches "todo", "html", "man"
|
||||
<2> Delete "test" branch even if the "master" branch does not have all
|
||||
commits from test branch.
|
||||
|
||||
|
||||
|
||||
@@ -9,17 +9,17 @@ git-config - Get and set repository or global options
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-config' [--system | --global] [type] [-z|--null] name [value [value_regex]]
|
||||
'git-config' [--system | --global] [type] --add name value
|
||||
'git-config' [--system | --global] [type] --replace-all name [value [value_regex]]
|
||||
'git-config' [--system | --global] [type] [-z|--null] --get name [value_regex]
|
||||
'git-config' [--system | --global] [type] [-z|--null] --get-all name [value_regex]
|
||||
'git-config' [--system | --global] [type] [-z|--null] --get-regexp name_regex [value_regex]
|
||||
'git-config' [--system | --global] --unset name [value_regex]
|
||||
'git-config' [--system | --global] --unset-all name [value_regex]
|
||||
'git-config' [--system | --global] --rename-section old_name new_name
|
||||
'git-config' [--system | --global] --remove-section name
|
||||
'git-config' [--system | --global] [-z|--null] -l | --list
|
||||
'git-config' [<file-option>] [type] [-z|--null] name [value [value_regex]]
|
||||
'git-config' [<file-option>] [type] --add name value
|
||||
'git-config' [<file-option>] [type] --replace-all name [value [value_regex]]
|
||||
'git-config' [<file-option>] [type] [-z|--null] --get name [value_regex]
|
||||
'git-config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
|
||||
'git-config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
|
||||
'git-config' [<file-option>] --unset name [value_regex]
|
||||
'git-config' [<file-option>] --unset-all name [value_regex]
|
||||
'git-config' [<file-option>] --rename-section old_name new_name
|
||||
'git-config' [<file-option>] --remove-section name
|
||||
'git-config' [<file-option>] [-z|--null] -l | --list
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -40,10 +40,16 @@ convert the value to the canonical form (simple decimal number for int,
|
||||
a "true" or "false" string for bool). If no type specifier is passed,
|
||||
no checks or transformations are performed on the value.
|
||||
|
||||
The file-option can be one of '--system', '--global' or '--file'
|
||||
which specify where the values will be read from or written to.
|
||||
The default is to assume the config file of the current repository,
|
||||
.git/config unless defined otherwise with GIT_DIR and GIT_CONFIG
|
||||
(see <<FILES>>).
|
||||
|
||||
This command will fail if:
|
||||
|
||||
. The .git/config file is invalid,
|
||||
. Can not write to .git/config,
|
||||
. The config file is invalid,
|
||||
. Can not write to the config file,
|
||||
. no section was provided,
|
||||
. the section or key is invalid,
|
||||
. you try to unset an option which does not exist,
|
||||
@@ -93,6 +99,9 @@ rather than from all available files.
|
||||
+
|
||||
See also <<FILES>>.
|
||||
|
||||
-f config-file, --file config-file::
|
||||
Use the given config file instead of the one specified by GIT_CONFIG.
|
||||
|
||||
--remove-section::
|
||||
Remove the given section from the configuration file.
|
||||
|
||||
@@ -130,8 +139,8 @@ See also <<FILES>>.
|
||||
FILES
|
||||
-----
|
||||
|
||||
There are three files where git-config will search for configuration
|
||||
options:
|
||||
If not set explicitely with '--file', there are three files where
|
||||
git-config will search for configuration options:
|
||||
|
||||
.git/config::
|
||||
Repository specific configuration file. (The filename is
|
||||
@@ -205,9 +214,7 @@ Given a .git/config like this:
|
||||
|
||||
; Proxy settings
|
||||
[core]
|
||||
gitproxy="ssh" for "ssh://kernel.org/"
|
||||
gitproxy="proxy-command" for kernel.org
|
||||
gitproxy="myprotocol-command" for "my://"
|
||||
gitproxy=default-proxy ; for all the rest
|
||||
|
||||
you can set the filemode to true with
|
||||
@@ -282,7 +289,7 @@ To actually match only values with an exclamation mark, you have to
|
||||
To add a new proxy, without altering any of the existing ones, use
|
||||
|
||||
------------
|
||||
% git config core.gitproxy '"proxy" for example.com'
|
||||
% git config core.gitproxy '"proxy-command" for example.com'
|
||||
------------
|
||||
|
||||
|
||||
|
||||
@@ -54,6 +54,12 @@ OPTIONS
|
||||
'git://example.com/hello.git', `git-daemon` will interpret the path
|
||||
as '/srv/git/hello.git'.
|
||||
|
||||
--base-path-relaxed::
|
||||
If --base-path is enabled and repo lookup fails, with this option
|
||||
`git-daemon` will attempt to lookup without prefixing the base path.
|
||||
This is useful for switching to --base-path usage, while still
|
||||
allowing the old paths.
|
||||
|
||||
--interpolated-path=pathtemplate::
|
||||
To support virtual hosting, an interpolated path template can be
|
||||
used to dynamically construct alternate paths. The template
|
||||
|
||||
@@ -76,10 +76,10 @@ $ git diff --cached <2>
|
||||
$ git diff HEAD <3>
|
||||
------------
|
||||
+
|
||||
<1> changes in the working tree not yet staged for the next commit.
|
||||
<2> changes between the index and your last commit; what you
|
||||
<1> Changes in the working tree not yet staged for the next commit.
|
||||
<2> Changes between the index and your last commit; what you
|
||||
would be committing if you run "git commit" without "-a" option.
|
||||
<3> changes in the working tree since your last commit; what you
|
||||
<3> Changes in the working tree since your last commit; what you
|
||||
would be committing if you run "git commit -a"
|
||||
|
||||
Comparing with arbitrary commits::
|
||||
@@ -90,12 +90,12 @@ $ git diff HEAD -- ./test <2>
|
||||
$ git diff HEAD^ HEAD <3>
|
||||
------------
|
||||
+
|
||||
<1> instead of using the tip of the current branch, compare with the
|
||||
<1> Instead of using the tip of the current branch, compare with the
|
||||
tip of "test" branch.
|
||||
<2> instead of comparing with the tip of "test" branch, compare with
|
||||
<2> Instead of comparing with the tip of "test" branch, compare with
|
||||
the tip of the current branch, but limit the comparison to the
|
||||
file "test".
|
||||
<3> compare the version before the last commit and the last commit.
|
||||
<3> Compare the version before the last commit and the last commit.
|
||||
|
||||
|
||||
Limiting the diff output::
|
||||
@@ -106,11 +106,11 @@ $ git diff --name-status <2>
|
||||
$ git diff arch/i386 include/asm-i386 <3>
|
||||
------------
|
||||
+
|
||||
<1> show only modification, rename and copy, but not addition
|
||||
<1> Show only modification, rename and copy, but not addition
|
||||
nor deletion.
|
||||
<2> show only names and the nature of change, but not actual
|
||||
<2> Show only names and the nature of change, but not actual
|
||||
diff output.
|
||||
<3> limit diff output to named subtrees.
|
||||
<3> Limit diff output to named subtrees.
|
||||
|
||||
Munging the diff output::
|
||||
+
|
||||
@@ -119,9 +119,9 @@ $ git diff --find-copies-harder -B -C <1>
|
||||
$ git diff -R <2>
|
||||
------------
|
||||
+
|
||||
<1> spend extra cycles to find renames, copies and complete
|
||||
<1> Spend extra cycles to find renames, copies and complete
|
||||
rewrites (very expensive).
|
||||
<2> output diff in reverse.
|
||||
<2> Output diff in reverse.
|
||||
|
||||
|
||||
Author
|
||||
|
||||
@@ -107,11 +107,11 @@ pull after you are done and ready.
|
||||
|
||||
When things cleanly merge, these things happen:
|
||||
|
||||
1. the results are updated both in the index file and in your
|
||||
working tree,
|
||||
2. index file is written out as a tree,
|
||||
3. the tree gets committed, and
|
||||
4. the `HEAD` pointer gets advanced.
|
||||
1. The results are updated both in the index file and in your
|
||||
working tree;
|
||||
2. Index file is written out as a tree;
|
||||
3. The tree gets committed; and
|
||||
4. The `HEAD` pointer gets advanced.
|
||||
|
||||
Because of 2., we require that the original state of the index
|
||||
file to match exactly the current `HEAD` commit; otherwise we
|
||||
|
||||
@@ -63,7 +63,7 @@ $ git commit -a -c ORIG_HEAD <3>
|
||||
<1> This is most often done when you remembered what you
|
||||
just committed is incomplete, or you misspelled your commit
|
||||
message, or both. Leaves working tree as it was before "reset".
|
||||
<2> make corrections to working tree files.
|
||||
<2> Make corrections to working tree files.
|
||||
<3> "reset" copies the old head to .git/ORIG_HEAD; redo the
|
||||
commit by starting with its log message. If you do not need to
|
||||
edit the message further, you can give -C option instead.
|
||||
@@ -106,17 +106,17 @@ $ git reset <3>
|
||||
$ git pull git://info.example.com/ nitfol <4>
|
||||
------------
|
||||
+
|
||||
<1> you are happily working on something, and find the changes
|
||||
<1> You are happily working on something, and find the changes
|
||||
in these files are in good order. You do not want to see them
|
||||
when you run "git diff", because you plan to work on other files
|
||||
and changes with these files are distracting.
|
||||
<2> somebody asks you to pull, and the changes sounds worthy of merging.
|
||||
<3> however, you already dirtied the index (i.e. your index does
|
||||
<2> Somebody asks you to pull, and the changes sounds worthy of merging.
|
||||
<3> However, you already dirtied the index (i.e. your index does
|
||||
not match the HEAD commit). But you know the pull you are going
|
||||
to make does not affect frotz.c nor filfre.c, so you revert the
|
||||
index changes for these two files. Your changes in working tree
|
||||
remain there.
|
||||
<4> then you can pull and merge, leaving frotz.c and filfre.c
|
||||
<4> Then you can pull and merge, leaving frotz.c and filfre.c
|
||||
changes still in the working tree.
|
||||
|
||||
Undo a merge or pull::
|
||||
@@ -133,15 +133,15 @@ Fast forward
|
||||
$ git reset --hard ORIG_HEAD <4>
|
||||
------------
|
||||
+
|
||||
<1> try to update from the upstream resulted in a lot of
|
||||
<1> Try to update from the upstream resulted in a lot of
|
||||
conflicts; you were not ready to spend a lot of time merging
|
||||
right now, so you decide to do that later.
|
||||
<2> "pull" has not made merge commit, so "git reset --hard"
|
||||
which is a synonym for "git reset --hard HEAD" clears the mess
|
||||
from the index file and the working tree.
|
||||
<3> merge a topic branch into the current branch, which resulted
|
||||
<3> Merge a topic branch into the current branch, which resulted
|
||||
in a fast forward.
|
||||
<4> but you decided that the topic branch is not ready for public
|
||||
<4> But you decided that the topic branch is not ready for public
|
||||
consumption yet. "pull" or "merge" always leaves the original
|
||||
tip of the current branch in ORIG_HEAD, so resetting hard to it
|
||||
brings your index file and the working tree back to that state,
|
||||
|
||||
@@ -405,7 +405,7 @@ the attributes given to path `t/abc` are computed as follows:
|
||||
and `bar` attributes should be given to this path, so it
|
||||
leaves `foo` and `bar` unset. Attribute `baz` is set.
|
||||
|
||||
3. Finally it examines `$GIT_DIR/info/gitattributes`. This file
|
||||
3. Finally it examines `$GIT_DIR/info/attributes`. This file
|
||||
is used to override the in-tree settings. The first line is
|
||||
a match, and `foo` is set, `bar` is reverted to unspecified
|
||||
state, and `baz` is unset.
|
||||
|
||||
23
Makefile
23
Makefile
@@ -151,6 +151,7 @@ sysconfdir = /etc
|
||||
else
|
||||
sysconfdir = $(prefix)/etc
|
||||
endif
|
||||
lib = lib
|
||||
ETC_GITCONFIG = $(sysconfdir)/gitconfig
|
||||
# DESTDIR=
|
||||
|
||||
@@ -374,7 +375,7 @@ BUILTIN_OBJS = \
|
||||
builtin-pack-refs.o
|
||||
|
||||
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
||||
EXTLIBS = -lz
|
||||
EXTLIBS =
|
||||
|
||||
#
|
||||
# Platform specific tweaks
|
||||
@@ -458,6 +459,10 @@ ifeq ($(uname_S),AIX)
|
||||
NO_STRLCPY = YesPlease
|
||||
NEEDS_LIBICONV=YesPlease
|
||||
endif
|
||||
ifeq ($(uname_S),GNU)
|
||||
# GNU/Hurd
|
||||
NO_STRLCPY=YesPlease
|
||||
endif
|
||||
ifeq ($(uname_S),IRIX64)
|
||||
NO_IPV6=YesPlease
|
||||
NO_SETENV=YesPlease
|
||||
@@ -531,9 +536,9 @@ endif
|
||||
|
||||
ifndef NO_CURL
|
||||
ifdef CURLDIR
|
||||
# Try "-Wl,-rpath=$(CURLDIR)/lib" in such a case.
|
||||
# Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case.
|
||||
BASIC_CFLAGS += -I$(CURLDIR)/include
|
||||
CURL_LIBCURL = -L$(CURLDIR)/lib $(CC_LD_DYNPATH)$(CURLDIR)/lib -lcurl
|
||||
CURL_LIBCURL = -L$(CURLDIR)/$(lib) $(CC_LD_DYNPATH)$(CURLDIR)/$(lib) -lcurl
|
||||
else
|
||||
CURL_LIBCURL = -lcurl
|
||||
endif
|
||||
@@ -549,11 +554,17 @@ ifndef NO_CURL
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef ZLIB_PATH
|
||||
BASIC_CFLAGS += -I$(ZLIB_PATH)/include
|
||||
EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
|
||||
endif
|
||||
EXTLIBS += -lz
|
||||
|
||||
ifndef NO_OPENSSL
|
||||
OPENSSL_LIBSSL = -lssl
|
||||
ifdef OPENSSLDIR
|
||||
BASIC_CFLAGS += -I$(OPENSSLDIR)/include
|
||||
OPENSSL_LINK = -L$(OPENSSLDIR)/lib $(CC_LD_DYNPATH)$(OPENSSLDIR)/lib
|
||||
OPENSSL_LINK = -L$(OPENSSLDIR)/$(lib) $(CC_LD_DYNPATH)$(OPENSSLDIR)/$(lib)
|
||||
else
|
||||
OPENSSL_LINK =
|
||||
endif
|
||||
@@ -570,7 +581,7 @@ endif
|
||||
ifdef NEEDS_LIBICONV
|
||||
ifdef ICONVDIR
|
||||
BASIC_CFLAGS += -I$(ICONVDIR)/include
|
||||
ICONV_LINK = -L$(ICONVDIR)/lib $(CC_LD_DYNPATH)$(ICONVDIR)/lib
|
||||
ICONV_LINK = -L$(ICONVDIR)/$(lib) $(CC_LD_DYNPATH)$(ICONVDIR)/$(lib)
|
||||
else
|
||||
ICONV_LINK =
|
||||
endif
|
||||
@@ -968,7 +979,7 @@ endif
|
||||
|
||||
### Testing rules
|
||||
|
||||
TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X
|
||||
TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X
|
||||
|
||||
all: $(TEST_PROGRAMS)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "cache.h"
|
||||
|
||||
static const char git_config_set_usage[] =
|
||||
"git-config [ --global | --system ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
|
||||
"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
|
||||
|
||||
static char *key;
|
||||
static regex_t *key_regexp;
|
||||
@@ -186,6 +186,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
else if (!strcmp(argv[1], "--system"))
|
||||
setenv(CONFIG_ENVIRONMENT, git_etc_gitconfig(), 1);
|
||||
else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
|
||||
if (argc < 3)
|
||||
usage(git_config_set_usage);
|
||||
setenv(CONFIG_ENVIRONMENT, argv[2], 1);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
|
||||
term = '\0';
|
||||
delim = '\n';
|
||||
|
||||
@@ -184,36 +184,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the full path to the working tree specified in $GIT_WORK_TREE
|
||||
* or NULL if no working tree is specified.
|
||||
*/
|
||||
static const char *get_work_tree(void)
|
||||
{
|
||||
const char *git_work_tree;
|
||||
char cwd[PATH_MAX];
|
||||
static char worktree[PATH_MAX];
|
||||
|
||||
git_work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||
if (!git_work_tree)
|
||||
return NULL;
|
||||
if (!getcwd(cwd, sizeof(cwd)))
|
||||
die("Unable to read current working directory");
|
||||
if (chdir(git_work_tree))
|
||||
die("Cannot change directory to specified working tree '%s'",
|
||||
git_work_tree);
|
||||
if (git_work_tree[0] != '/') {
|
||||
if (!getcwd(worktree, sizeof(worktree)))
|
||||
die("Unable to read current working directory");
|
||||
git_work_tree = worktree;
|
||||
}
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
return git_work_tree;
|
||||
}
|
||||
|
||||
static int create_default_files(const char *git_dir, const char *git_work_tree,
|
||||
const char *template_path)
|
||||
static int create_default_files(const char *git_dir, const char *template_path)
|
||||
{
|
||||
unsigned len = strlen(git_dir);
|
||||
static char path[PATH_MAX];
|
||||
@@ -292,16 +263,16 @@ static int create_default_files(const char *git_dir, const char *git_work_tree,
|
||||
}
|
||||
git_config_set("core.filemode", filemode ? "true" : "false");
|
||||
|
||||
if (is_bare_repository() && !git_work_tree) {
|
||||
if (is_bare_repository())
|
||||
git_config_set("core.bare", "true");
|
||||
}
|
||||
else {
|
||||
const char *work_tree = get_git_work_tree();
|
||||
git_config_set("core.bare", "false");
|
||||
/* allow template config file to override the default */
|
||||
if (log_all_ref_updates == -1)
|
||||
git_config_set("core.logallrefupdates", "true");
|
||||
if (git_work_tree)
|
||||
git_config_set("core.worktree", git_work_tree);
|
||||
if (work_tree != git_work_tree_cfg)
|
||||
git_config_set("core.worktree", work_tree);
|
||||
}
|
||||
return reinit;
|
||||
}
|
||||
@@ -318,7 +289,6 @@ static const char init_db_usage[] =
|
||||
int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *git_dir;
|
||||
const char *git_work_tree;
|
||||
const char *sha1_dir;
|
||||
const char *template_dir = NULL;
|
||||
char *path;
|
||||
@@ -339,7 +309,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
usage(init_db_usage);
|
||||
}
|
||||
|
||||
git_work_tree = get_work_tree();
|
||||
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
|
||||
if (!getcwd(git_work_tree_cfg, PATH_MAX))
|
||||
die ("Cannot access current working directory.");
|
||||
if (access(get_git_work_tree(), X_OK))
|
||||
die ("Cannot access work tree '%s'", get_git_work_tree());
|
||||
|
||||
/*
|
||||
* Set up the default .git directory contents
|
||||
@@ -356,7 +330,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
check_repository_format();
|
||||
|
||||
reinit = create_default_files(git_dir, git_work_tree, template_dir);
|
||||
reinit = create_default_files(git_dir, template_dir);
|
||||
|
||||
/*
|
||||
* And set up the object store.
|
||||
|
||||
@@ -469,9 +469,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
break;
|
||||
}
|
||||
|
||||
if (require_work_tree &&
|
||||
(!is_inside_work_tree() || is_inside_git_dir()))
|
||||
die("This operation must be run in a work tree");
|
||||
if (require_work_tree && !is_inside_work_tree()) {
|
||||
const char *work_tree = get_git_work_tree();
|
||||
if (!work_tree || chdir(work_tree))
|
||||
die("This operation must be run in a work tree");
|
||||
}
|
||||
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
|
||||
@@ -237,8 +237,6 @@ static int eatspace(char *line)
|
||||
|
||||
static char *cleanup_subject(char *subject)
|
||||
{
|
||||
if (keep_subject)
|
||||
return subject;
|
||||
for (;;) {
|
||||
char *p;
|
||||
int len, remove;
|
||||
@@ -425,6 +423,7 @@ static int read_one_header_line(char *line, int sz, FILE *in)
|
||||
if (addlen >= sz - len)
|
||||
addlen = sz - len - 1;
|
||||
memcpy(line + len, continuation, addlen);
|
||||
line[len] = '\n';
|
||||
len += addlen;
|
||||
}
|
||||
}
|
||||
@@ -846,6 +845,22 @@ static void handle_body(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static void output_header_lines(FILE *fout, const char *hdr, char *data)
|
||||
{
|
||||
while (1) {
|
||||
char *ep = strchr(data, '\n');
|
||||
int len;
|
||||
if (!ep)
|
||||
len = strlen(data);
|
||||
else
|
||||
len = ep - data;
|
||||
fprintf(fout, "%s: %.*s\n", hdr, len, data);
|
||||
if (!ep)
|
||||
break;
|
||||
data = ep + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_info(void)
|
||||
{
|
||||
char *sub;
|
||||
@@ -863,9 +878,13 @@ static void handle_info(void)
|
||||
continue;
|
||||
|
||||
if (!memcmp(header[i], "Subject", 7)) {
|
||||
sub = cleanup_subject(hdr);
|
||||
cleanup_space(sub);
|
||||
fprintf(fout, "Subject: %s\n", sub);
|
||||
if (keep_subject)
|
||||
sub = hdr;
|
||||
else {
|
||||
sub = cleanup_subject(hdr);
|
||||
cleanup_space(sub);
|
||||
}
|
||||
output_header_lines(fout, "Subject", sub);
|
||||
} else if (!memcmp(header[i], "From", 4)) {
|
||||
handle_from(hdr);
|
||||
fprintf(fout, "Author: %s\n", name);
|
||||
|
||||
@@ -97,7 +97,6 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.head_idx = -1;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_locked_index(&lock_file, 1);
|
||||
|
||||
@@ -300,7 +300,7 @@ static struct commit_list *find_bisection(struct commit_list *list,
|
||||
show_list("bisection 2 sorted", 0, nr, list);
|
||||
|
||||
*all = nr;
|
||||
weights = xcalloc(on_list, sizeof(int*));
|
||||
weights = xcalloc(on_list, sizeof(*weights));
|
||||
counted = 0;
|
||||
|
||||
for (n = 0, p = list; p; p = p->next) {
|
||||
|
||||
@@ -321,6 +321,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!strcmp(arg, "--show-cdup")) {
|
||||
const char *pfx = prefix;
|
||||
if (!is_inside_work_tree()) {
|
||||
const char *work_tree =
|
||||
get_git_work_tree();
|
||||
if (work_tree)
|
||||
printf("%s\n", work_tree);
|
||||
continue;
|
||||
}
|
||||
while (pfx) {
|
||||
pfx = strchr(pfx, '/');
|
||||
if (pfx) {
|
||||
|
||||
@@ -43,8 +43,6 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
msg = argv[1];
|
||||
if (!*msg)
|
||||
die("Refusing to perform update with empty message");
|
||||
if (strchr(msg, '\n'))
|
||||
die("Refusing to perform update with \\n in message");
|
||||
}
|
||||
else if (!strcmp("--", arg)) {
|
||||
argc--;
|
||||
|
||||
@@ -23,8 +23,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||
msg = argv[++i];
|
||||
if (!*msg)
|
||||
die("Refusing to perform update with empty message.");
|
||||
if (strchr(msg, '\n'))
|
||||
die("Refusing to perform update with \\n in message.");
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-d", argv[i])) {
|
||||
|
||||
8
cache.h
8
cache.h
@@ -208,12 +208,15 @@ enum object_type {
|
||||
extern int is_bare_repository_cfg;
|
||||
extern int is_bare_repository(void);
|
||||
extern int is_inside_git_dir(void);
|
||||
extern char *git_work_tree_cfg;
|
||||
extern int is_inside_work_tree(void);
|
||||
extern const char *get_git_dir(void);
|
||||
extern char *get_object_directory(void);
|
||||
extern char *get_refs_directory(void);
|
||||
extern char *get_index_file(void);
|
||||
extern char *get_graft_file(void);
|
||||
extern int set_git_dir(const char *path);
|
||||
extern const char *get_git_work_tree(void);
|
||||
|
||||
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
||||
|
||||
@@ -359,6 +362,11 @@ int git_config_perm(const char *var, const char *value);
|
||||
int adjust_shared_perm(const char *path);
|
||||
int safe_create_leading_directories(char *path);
|
||||
char *enter_repo(char *path, int strict);
|
||||
static inline int is_absolute_path(const char *path)
|
||||
{
|
||||
return path[0] == '/';
|
||||
}
|
||||
const char *make_absolute_path(const char *path);
|
||||
|
||||
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
|
||||
extern int sha1_object_info(const unsigned char *, unsigned long *);
|
||||
|
||||
32
config.c
32
config.c
@@ -731,7 +731,7 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
int fd = -1, in_fd;
|
||||
int ret;
|
||||
char* config_filename;
|
||||
char* lock_file;
|
||||
struct lock_file *lock = NULL;
|
||||
const char* last_dot = strrchr(key, '.');
|
||||
|
||||
config_filename = getenv(CONFIG_ENVIRONMENT);
|
||||
@@ -741,7 +741,6 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
config_filename = git_path("config");
|
||||
}
|
||||
config_filename = xstrdup(config_filename);
|
||||
lock_file = xstrdup(mkpath("%s.lock", config_filename));
|
||||
|
||||
/*
|
||||
* Since "key" actually contains the section name and the real
|
||||
@@ -786,11 +785,12 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
store.key[i] = 0;
|
||||
|
||||
/*
|
||||
* The lock_file serves a purpose in addition to locking: the new
|
||||
* The lock serves a purpose in addition to locking: the new
|
||||
* contents of .git/config will be written into it.
|
||||
*/
|
||||
fd = open(lock_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||
if (fd < 0 || adjust_shared_perm(lock_file)) {
|
||||
lock = xcalloc(sizeof(struct lock_file), 1);
|
||||
fd = hold_lock_file_for_update(lock, config_filename, 0);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "could not lock config file\n");
|
||||
free(store.key);
|
||||
ret = -1;
|
||||
@@ -930,27 +930,31 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
goto write_err_out;
|
||||
|
||||
munmap(contents, contents_sz);
|
||||
unlink(config_filename);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
fd = -1;
|
||||
if (rename(lock_file, config_filename) < 0) {
|
||||
fprintf(stderr, "Could not rename the lock file?\n");
|
||||
if (close(fd) || commit_lock_file(lock) < 0) {
|
||||
fprintf(stderr, "Cannot commit config file!\n");
|
||||
ret = 4;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* fd is closed, so don't try to close it below. */
|
||||
fd = -1;
|
||||
/*
|
||||
* lock is committed, so don't try to roll it back below.
|
||||
* NOTE: Since lockfile.c keeps a linked list of all created
|
||||
* lock_file structures, it isn't safe to free(lock). It's
|
||||
* better to just leave it hanging around.
|
||||
*/
|
||||
lock = NULL;
|
||||
ret = 0;
|
||||
|
||||
out_free:
|
||||
if (0 <= fd)
|
||||
close(fd);
|
||||
if (lock)
|
||||
rollback_lock_file(lock);
|
||||
free(config_filename);
|
||||
if (lock_file) {
|
||||
unlink(lock_file);
|
||||
free(lock_file);
|
||||
}
|
||||
return ret;
|
||||
|
||||
write_err_out:
|
||||
|
||||
14
configure.ac
14
configure.ac
@@ -69,12 +69,26 @@ fi \
|
||||
## Site configuration related to programs (before tests)
|
||||
## --with-PACKAGE[=ARG] and --without-PACKAGE
|
||||
#
|
||||
# Set lib to alternative name of lib directory (e.g. lib64)
|
||||
AC_ARG_WITH([lib],
|
||||
[AS_HELP_STRING([--with-lib=ARG],
|
||||
[ARG specifies alternative name for lib directory])],
|
||||
[if test "$withval" = "no" -o "$withval" = "yes"; then \
|
||||
AC_MSG_WARN([You should provide name for --with-lib=ARG]); \
|
||||
else \
|
||||
GIT_CONF_APPEND_LINE(lib=$withval); \
|
||||
fi; \
|
||||
],[])
|
||||
#
|
||||
# Define SHELL_PATH to provide path to shell.
|
||||
GIT_ARG_SET_PATH(shell)
|
||||
#
|
||||
# Define PERL_PATH to provide path to Perl.
|
||||
GIT_ARG_SET_PATH(perl)
|
||||
#
|
||||
# Define ZLIB_PATH to provide path to zlib.
|
||||
GIT_ARG_SET_PATH(zlib)
|
||||
#
|
||||
# Declare the with-tcltk/without-tcltk options.
|
||||
AC_ARG_WITH(tcltk,
|
||||
AS_HELP_STRING([--with-tcltk],[use Tcl/Tk GUI (default is YES)])
|
||||
|
||||
@@ -530,7 +530,7 @@ and returns the process output as a string."
|
||||
(setf (git-fileinfo->needs-refresh info) t)
|
||||
(when node ;preserve the marked flag
|
||||
(setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node))))
|
||||
(if node (ewoc-set-data node info) (ewoc-enter-last status info))))
|
||||
(if node (setf (ewoc-data node) info) (ewoc-enter-last status info))))
|
||||
|
||||
(defun git-run-diff-index (status files)
|
||||
"Run git-diff-index on FILES and parse the results into STATUS.
|
||||
@@ -589,6 +589,16 @@ Return the list of files that haven't been handled."
|
||||
(when node (push (ewoc-data node) unmerged-files))))
|
||||
(git-set-files-state unmerged-files 'unmerged))))
|
||||
|
||||
(defun git-get-exclude-files ()
|
||||
"Get the list of exclude files to pass to git-ls-files."
|
||||
(let (files
|
||||
(config (git-config "core.excludesfile")))
|
||||
(when (file-readable-p ".git/info/exclude")
|
||||
(push ".git/info/exclude" files))
|
||||
(when (and config (file-readable-p config))
|
||||
(push config files))
|
||||
files))
|
||||
|
||||
(defun git-update-status-files (files &optional default-state)
|
||||
"Update the status of FILES from the index."
|
||||
(unless git-status (error "Not in git-status buffer."))
|
||||
@@ -598,11 +608,11 @@ Return the list of files that haven't been handled."
|
||||
(git-run-ls-files status files 'added "-c")
|
||||
(git-run-diff-index status files))))
|
||||
(git-run-ls-unmerged status files)
|
||||
(when (and (or (not files) remaining-files)
|
||||
(file-readable-p ".git/info/exclude"))
|
||||
(setq remaining-files (git-run-ls-files status remaining-files
|
||||
'unknown "-o" "--exclude-from=.git/info/exclude"
|
||||
(concat "--exclude-per-directory=" git-per-dir-ignore-file))))
|
||||
(when (or (not files) remaining-files)
|
||||
(let ((exclude-files (git-get-exclude-files)))
|
||||
(setq remaining-files (apply #'git-run-ls-files status remaining-files 'unknown "-o"
|
||||
(concat "--exclude-per-directory=" git-per-dir-ignore-file)
|
||||
(mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
|
||||
; mark remaining files with the default state (or remove them if nil)
|
||||
(when remaining-files
|
||||
(if default-state
|
||||
|
||||
@@ -1181,11 +1181,11 @@ class P4Sync(Command):
|
||||
elif ',' not in self.changeRange:
|
||||
self.revision = self.changeRange
|
||||
self.changeRange = ""
|
||||
p = p[0:atIdx]
|
||||
p = p[:atIdx]
|
||||
elif p.find("#") != -1:
|
||||
hashIdx = p.index("#")
|
||||
self.revision = p[hashIdx:]
|
||||
p = p[0:hashIdx]
|
||||
p = p[:hashIdx]
|
||||
elif self.previousDepotPaths == []:
|
||||
self.revision = "#head"
|
||||
|
||||
@@ -1296,10 +1296,10 @@ class P4Sync(Command):
|
||||
changeNum = line.split(" ")[1]
|
||||
changes.append(changeNum)
|
||||
|
||||
changes.reverse()
|
||||
changes.sort()
|
||||
|
||||
if len(self.maxChanges) > 0:
|
||||
changes = changes[0:min(int(self.maxChanges), len(changes))]
|
||||
changes = changes[:min(int(self.maxChanges), len(changes))]
|
||||
|
||||
if len(changes) == 0:
|
||||
if not self.silent:
|
||||
|
||||
26
daemon.c
26
daemon.c
@@ -16,7 +16,8 @@ static int reuseaddr;
|
||||
static const char daemon_usage[] =
|
||||
"git-daemon [--verbose] [--syslog] [--export-all]\n"
|
||||
" [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
|
||||
" [--base-path=path] [--user-path | --user-path=path]\n"
|
||||
" [--base-path=path] [--base-path-relaxed]\n"
|
||||
" [--user-path | --user-path=path]\n"
|
||||
" [--interpolated-path=path]\n"
|
||||
" [--reuseaddr] [--detach] [--pid-file=file]\n"
|
||||
" [--[enable|disable|allow-override|forbid-override]=service]\n"
|
||||
@@ -34,6 +35,7 @@ static int export_all_trees;
|
||||
/* Take all paths relative to this one if non-NULL */
|
||||
static char *base_path;
|
||||
static char *interpolated_path;
|
||||
static int base_path_relaxed;
|
||||
|
||||
/* Flag indicating client sent extra args. */
|
||||
static int saw_extended_args;
|
||||
@@ -180,6 +182,7 @@ static char *path_ok(struct interp *itable)
|
||||
{
|
||||
static char rpath[PATH_MAX];
|
||||
static char interp_path[PATH_MAX];
|
||||
int retried_path = 0;
|
||||
char *path;
|
||||
char *dir;
|
||||
|
||||
@@ -235,7 +238,22 @@ static char *path_ok(struct interp *itable)
|
||||
dir = rpath;
|
||||
}
|
||||
|
||||
path = enter_repo(dir, strict_paths);
|
||||
do {
|
||||
path = enter_repo(dir, strict_paths);
|
||||
if (path)
|
||||
break;
|
||||
|
||||
/*
|
||||
* if we fail and base_path_relaxed is enabled, try without
|
||||
* prefixing the base path
|
||||
*/
|
||||
if (base_path && base_path_relaxed && !retried_path) {
|
||||
dir = itable[INTERP_SLOT_DIR].value;
|
||||
retried_path = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
if (!path) {
|
||||
logerror("'%s': unable to chdir or not a git archive", dir);
|
||||
@@ -1061,6 +1079,10 @@ int main(int argc, char **argv)
|
||||
base_path = arg+12;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--base-path-relaxed")) {
|
||||
base_path_relaxed = 1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--interpolated-path=")) {
|
||||
interpolated_path = arg+20;
|
||||
continue;
|
||||
|
||||
43
dir.c
43
dir.c
@@ -642,3 +642,46 @@ file_exists(const char *f)
|
||||
struct stat sb;
|
||||
return stat(f, &sb) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_relative_cwd() gets the prefix of the current working directory
|
||||
* relative to 'dir'. If we are not inside 'dir', it returns NULL.
|
||||
*
|
||||
* As a convenience, it also returns NULL if 'dir' is already NULL. The
|
||||
* reason for this behaviour is that it is natural for functions returning
|
||||
* directory names to return NULL to say "this directory does not exist"
|
||||
* or "this directory is invalid". These cases are usually handled the
|
||||
* same as if the cwd is not inside 'dir' at all, so get_relative_cwd()
|
||||
* returns NULL for both of them.
|
||||
*
|
||||
* Most notably, get_relative_cwd(buffer, size, get_git_work_tree())
|
||||
* unifies the handling of "outside work tree" with "no work tree at all".
|
||||
*/
|
||||
char *get_relative_cwd(char *buffer, int size, const char *dir)
|
||||
{
|
||||
char *cwd = buffer;
|
||||
|
||||
if (!dir)
|
||||
return NULL;
|
||||
if (!getcwd(buffer, size))
|
||||
die("can't find the current directory: %s", strerror(errno));
|
||||
|
||||
if (!is_absolute_path(dir))
|
||||
dir = make_absolute_path(dir);
|
||||
|
||||
while (*dir && *dir == *cwd) {
|
||||
dir++;
|
||||
cwd++;
|
||||
}
|
||||
if (*dir)
|
||||
return NULL;
|
||||
if (*cwd == '/')
|
||||
return cwd + 1;
|
||||
return cwd;
|
||||
}
|
||||
|
||||
int is_inside_dir(const char *dir)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;
|
||||
}
|
||||
|
||||
3
dir.h
3
dir.h
@@ -61,4 +61,7 @@ extern void add_exclude(const char *string, const char *base,
|
||||
extern int file_exists(const char *);
|
||||
extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len);
|
||||
|
||||
extern char *get_relative_cwd(char *buffer, int size, const char *dir);
|
||||
extern int is_inside_dir(const char *dir);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,10 @@ int pager_in_use;
|
||||
int pager_use_color = 1;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
|
||||
/* This is set by setup_git_dir_gently() and/or git_default_config() */
|
||||
char *git_work_tree_cfg;
|
||||
static const char *work_tree;
|
||||
|
||||
static const char *git_dir;
|
||||
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
|
||||
|
||||
@@ -62,15 +66,8 @@ static void setup_git_env(void)
|
||||
|
||||
int is_bare_repository(void)
|
||||
{
|
||||
const char *dir, *s;
|
||||
if (0 <= is_bare_repository_cfg)
|
||||
return is_bare_repository_cfg;
|
||||
|
||||
dir = get_git_dir();
|
||||
if (!strcmp(dir, DEFAULT_GIT_DIR_ENVIRONMENT))
|
||||
return 0;
|
||||
s = strrchr(dir, '/');
|
||||
return !s || strcmp(s + 1, DEFAULT_GIT_DIR_ENVIRONMENT);
|
||||
/* if core.bare is not 'false', let's see if there is a work tree */
|
||||
return is_bare_repository_cfg && !get_git_work_tree();
|
||||
}
|
||||
|
||||
const char *get_git_dir(void)
|
||||
@@ -80,6 +77,26 @@ const char *get_git_dir(void)
|
||||
return git_dir;
|
||||
}
|
||||
|
||||
const char *get_git_work_tree(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||
/* core.bare = true overrides implicit and config work tree */
|
||||
if (!work_tree && is_bare_repository_cfg < 1) {
|
||||
work_tree = git_work_tree_cfg;
|
||||
/* make_absolute_path also normalizes the path */
|
||||
if (work_tree && !is_absolute_path(work_tree))
|
||||
work_tree = xstrdup(make_absolute_path(git_path(work_tree)));
|
||||
} else if (work_tree)
|
||||
work_tree = xstrdup(make_absolute_path(work_tree));
|
||||
initialized = 1;
|
||||
if (work_tree)
|
||||
is_bare_repository_cfg = 0;
|
||||
}
|
||||
return work_tree;
|
||||
}
|
||||
|
||||
char *get_object_directory(void)
|
||||
{
|
||||
if (!git_object_dir)
|
||||
@@ -107,3 +124,11 @@ char *get_graft_file(void)
|
||||
setup_git_env();
|
||||
return git_graft_file;
|
||||
}
|
||||
|
||||
int set_git_dir(const char *path)
|
||||
{
|
||||
if (setenv(GIT_DIR_ENVIRONMENT, path, 1))
|
||||
return error("Could not set GIT_DIR to '%s'", path);
|
||||
setup_git_env();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
use strict;
|
||||
|
||||
sub run_cmd_pipe {
|
||||
my $fh = undef;
|
||||
open($fh, '-|', @_) or die;
|
||||
return <$fh>;
|
||||
if ($^O eq 'MSWin32') {
|
||||
my @invalid = grep {m/[":*]/} @_;
|
||||
die "$^O does not support: @invalid\n" if @invalid;
|
||||
my @args = map { m/ /o ? "\"$_\"": $_ } @_;
|
||||
return qx{@args};
|
||||
} else {
|
||||
my $fh = undef;
|
||||
open($fh, '-|', @_) or die;
|
||||
return <$fh>;
|
||||
}
|
||||
}
|
||||
|
||||
my ($GIT_DIR) = run_cmd_pipe(qw(git rev-parse --git-dir));
|
||||
@@ -17,7 +24,7 @@ chomp($GIT_DIR);
|
||||
|
||||
sub refresh {
|
||||
my $fh;
|
||||
open $fh, '-|', qw(git update-index --refresh)
|
||||
open $fh, 'git update-index --refresh |'
|
||||
or die;
|
||||
while (<$fh>) {
|
||||
;# ignore 'needs update'
|
||||
@@ -296,7 +303,7 @@ sub revert_cmd {
|
||||
my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
|
||||
map { $_->{VALUE} } @update);
|
||||
my $fh;
|
||||
open $fh, '|-', qw(git update-index --index-info)
|
||||
open $fh, '| git update-index --index-info'
|
||||
or die;
|
||||
for (@lines) {
|
||||
print $fh $_;
|
||||
@@ -725,7 +732,7 @@ sub patch_update_cmd {
|
||||
if (@result) {
|
||||
my $fh;
|
||||
|
||||
open $fh, '|-', qw(git apply --cached);
|
||||
open $fh, '| git apply --cached';
|
||||
for (@{$head->{TEXT}}, @result) {
|
||||
print $fh $_;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,6 @@ $1"
|
||||
;;
|
||||
--a|--am|--ame|--amen|--amend)
|
||||
amend=t
|
||||
log_given=t$log_given
|
||||
use_commit=HEAD
|
||||
shift
|
||||
;;
|
||||
@@ -298,9 +297,9 @@ esac
|
||||
|
||||
case "$log_given" in
|
||||
tt*)
|
||||
die "Only one of -c/-C/-F/--amend can be used." ;;
|
||||
die "Only one of -c/-C/-F can be used." ;;
|
||||
*tm*|*mt*)
|
||||
die "Option -m cannot be combined with -c/-C/-F/--amend." ;;
|
||||
die "Option -m cannot be combined with -c/-C/-F." ;;
|
||||
esac
|
||||
|
||||
case "$#,$also,$only,$amend" in
|
||||
|
||||
@@ -405,6 +405,7 @@ do
|
||||
|
||||
require_clean_work_tree
|
||||
|
||||
mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
|
||||
if test ! -z "$2"
|
||||
then
|
||||
output git show-ref --verify --quiet "refs/heads/$2" ||
|
||||
@@ -418,7 +419,6 @@ do
|
||||
|
||||
test -z "$ONTO" && ONTO=$UPSTREAM
|
||||
|
||||
mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
|
||||
: > "$DOTEST"/interactive || die "Could not mark as interactive"
|
||||
git symbolic-ref HEAD > "$DOTEST"/head-name ||
|
||||
die "Could not get HEAD"
|
||||
@@ -463,8 +463,9 @@ do
|
||||
#
|
||||
EOF
|
||||
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
|
||||
--abbrev=7 --reverse $UPSTREAM..$HEAD | \
|
||||
sed "s/^/pick /" >> "$TODO"
|
||||
--abbrev=7 --reverse --left-right --cherry-pick \
|
||||
$UPSTREAM...$HEAD | \
|
||||
sed -n "s/^>/pick /p" >> "$TODO"
|
||||
|
||||
test -z "$(grep -ve '^$' -e '^#' < $TODO)" &&
|
||||
die_abort "Nothing to do"
|
||||
|
||||
@@ -29,7 +29,8 @@ set_reflog_action() {
|
||||
}
|
||||
|
||||
git_editor() {
|
||||
GIT_EDITOR=${GIT_EDITOR:-$(git config core.editor || echo ${VISUAL:-${EDITOR}})}
|
||||
: "${GIT_EDITOR:=$(git config core.editor)}"
|
||||
: "${GIT_EDITOR:=${VISUAL:-${EDITOR}}}"
|
||||
case "$GIT_EDITOR,$TERM" in
|
||||
,dumb)
|
||||
echo >&2 "No editor specified in GIT_EDITOR, core.editor, VISUAL,"
|
||||
@@ -40,7 +41,7 @@ git_editor() {
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
"${GIT_EDITOR:-vi}" "$1"
|
||||
eval "${GIT_EDITOR:=vi}" '"$@"'
|
||||
}
|
||||
|
||||
is_bare_repository () {
|
||||
@@ -59,8 +60,7 @@ cd_to_toplevel () {
|
||||
}
|
||||
|
||||
require_work_tree () {
|
||||
test $(git rev-parse --is-inside-work-tree) = true &&
|
||||
test $(git rev-parse --is-inside-git-dir) = false ||
|
||||
test $(git rev-parse --is-inside-work-tree) = true ||
|
||||
die "fatal: $0 cannot be used without a working tree."
|
||||
}
|
||||
|
||||
|
||||
39
git-svn.perl
39
git-svn.perl
@@ -938,8 +938,8 @@ sub resolve_local_globs {
|
||||
foreach (command(qw#for-each-ref --format=%(refname) refs/remotes#)) {
|
||||
next unless m#^refs/remotes/$ref->{regex}$#;
|
||||
my $p = $1;
|
||||
my $pathname = $path->full_path($p);
|
||||
my $refname = $ref->full_path($p);
|
||||
my $pathname = desanitize_refname($path->full_path($p));
|
||||
my $refname = desanitize_refname($ref->full_path($p));
|
||||
if (my $existing = $fetch->{$pathname}) {
|
||||
if ($existing ne $refname) {
|
||||
die "Refspec conflict:\n",
|
||||
@@ -1239,7 +1239,40 @@ sub new {
|
||||
$self;
|
||||
}
|
||||
|
||||
sub refname { "refs/remotes/$_[0]->{ref_id}" }
|
||||
sub refname {
|
||||
my ($refname) = "refs/remotes/$_[0]->{ref_id}" ;
|
||||
|
||||
# It cannot end with a slash /, we'll throw up on this because
|
||||
# SVN can't have directories with a slash in their name, either:
|
||||
if ($refname =~ m{/$}) {
|
||||
die "ref: '$refname' ends with a trailing slash, this is ",
|
||||
"not permitted by git nor Subversion\n";
|
||||
}
|
||||
|
||||
# It cannot have ASCII control character space, tilde ~, caret ^,
|
||||
# colon :, question-mark ?, asterisk *, space, or open bracket [
|
||||
# anywhere.
|
||||
#
|
||||
# Additionally, % must be escaped because it is used for escaping
|
||||
# and we want our escaped refname to be reversible
|
||||
$refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg;
|
||||
|
||||
# no slash-separated component can begin with a dot .
|
||||
# /.* becomes /%2E*
|
||||
$refname =~ s{/\.}{/%2E}g;
|
||||
|
||||
# It cannot have two consecutive dots .. anywhere
|
||||
# .. becomes %2E%2E
|
||||
$refname =~ s{\.\.}{%2E%2E}g;
|
||||
|
||||
return $refname;
|
||||
}
|
||||
|
||||
sub desanitize_refname {
|
||||
my ($refname) = @_;
|
||||
$refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg;
|
||||
return $refname;
|
||||
}
|
||||
|
||||
sub svm_uuid {
|
||||
my ($self) = @_;
|
||||
|
||||
21
git.c
21
git.c
@@ -276,9 +276,14 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv)
|
||||
prefix = setup_git_directory();
|
||||
if (p->option & USE_PAGER)
|
||||
setup_pager();
|
||||
if ((p->option & NEED_WORK_TREE) &&
|
||||
(!is_inside_work_tree() || is_inside_git_dir()))
|
||||
die("%s must be run in a work tree", p->cmd);
|
||||
if (p->option & NEED_WORK_TREE) {
|
||||
const char *work_tree = get_git_work_tree();
|
||||
const char *git_dir = get_git_dir();
|
||||
if (!is_absolute_path(git_dir))
|
||||
set_git_dir(make_absolute_path(git_dir));
|
||||
if (!work_tree || chdir(work_tree))
|
||||
die("%s must be run in a work tree", p->cmd);
|
||||
}
|
||||
trace_argv_printf(argv, argc, "trace: built-in: git");
|
||||
|
||||
status = p->fn(argc, argv, prefix);
|
||||
@@ -466,11 +471,11 @@ int main(int argc, const char **argv)
|
||||
cmd = argv[0];
|
||||
|
||||
/*
|
||||
* We search for git commands in the following order:
|
||||
* - git_exec_path()
|
||||
* - the path of the "git" command if we could find it
|
||||
* in $0
|
||||
* - the regular PATH.
|
||||
* We execute external git command via execv_git_cmd(),
|
||||
* which looks at "--exec-path" option, GIT_EXEC_PATH
|
||||
* environment, and $(gitexecdir) in Makefile while built,
|
||||
* in this order. For scripted commands, we prepend
|
||||
* the value of the exec_path variable to the PATH.
|
||||
*/
|
||||
if (exec_path)
|
||||
prepend_to_path(exec_path, strlen(exec_path));
|
||||
|
||||
@@ -1515,6 +1515,7 @@ sub git_get_projects_list {
|
||||
|
||||
File::Find::find({
|
||||
follow_fast => 1, # follow symbolic links
|
||||
follow_skip => 2, # ignore duplicates
|
||||
dangling_symlinks => 0, # ignore dangling symlinks, silently
|
||||
wanted => sub {
|
||||
# skip project-list toplevel, if we get it.
|
||||
|
||||
115
lockfile.c
115
lockfile.c
@@ -27,22 +27,109 @@ static void remove_lock_file_on_signal(int signo)
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
/*
|
||||
* p = absolute or relative path name
|
||||
*
|
||||
* Return a pointer into p showing the beginning of the last path name
|
||||
* element. If p is empty or the root directory ("/"), just return p.
|
||||
*/
|
||||
static char *last_path_elm(char *p)
|
||||
{
|
||||
/* r starts pointing to null at the end of the string */
|
||||
char *r = strchr(p, '\0');
|
||||
|
||||
if (r == p)
|
||||
return p; /* just return empty string */
|
||||
|
||||
r--; /* back up to last non-null character */
|
||||
|
||||
/* back up past trailing slashes, if any */
|
||||
while (r > p && *r == '/')
|
||||
r--;
|
||||
|
||||
/*
|
||||
* then go backwards until I hit a slash, or the beginning of
|
||||
* the string
|
||||
*/
|
||||
while (r > p && *(r-1) != '/')
|
||||
r--;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* We allow "recursive" symbolic links. Only within reason, though */
|
||||
#define MAXDEPTH 5
|
||||
|
||||
/*
|
||||
* p = path that may be a symlink
|
||||
* s = full size of p
|
||||
*
|
||||
* If p is a symlink, attempt to overwrite p with a path to the real
|
||||
* file or directory (which may or may not exist), following a chain of
|
||||
* symlinks if necessary. Otherwise, leave p unmodified.
|
||||
*
|
||||
* This is a best-effort routine. If an error occurs, p will either be
|
||||
* left unmodified or will name a different symlink in a symlink chain
|
||||
* that started with p's initial contents.
|
||||
*
|
||||
* Always returns p.
|
||||
*/
|
||||
|
||||
static char *resolve_symlink(char *p, size_t s)
|
||||
{
|
||||
int depth = MAXDEPTH;
|
||||
|
||||
while (depth--) {
|
||||
char link[PATH_MAX];
|
||||
int link_len = readlink(p, link, sizeof(link));
|
||||
if (link_len < 0) {
|
||||
/* not a symlink anymore */
|
||||
return p;
|
||||
}
|
||||
else if (link_len < sizeof(link))
|
||||
/* readlink() never null-terminates */
|
||||
link[link_len] = '\0';
|
||||
else {
|
||||
warning("%s: symlink too long", p);
|
||||
return p;
|
||||
}
|
||||
|
||||
if (link[0] == '/') {
|
||||
/* absolute path simply replaces p */
|
||||
if (link_len < s)
|
||||
strcpy(p, link);
|
||||
else {
|
||||
warning("%s: symlink too long", p);
|
||||
return p;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* link is a relative path, so I must replace the
|
||||
* last element of p with it.
|
||||
*/
|
||||
char *r = (char*)last_path_elm(p);
|
||||
if (r - p + link_len < s)
|
||||
strcpy(r, link);
|
||||
else {
|
||||
warning("%s: symlink too long", p);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static int lock_file(struct lock_file *lk, const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if ((!lstat(path, &st)) && S_ISLNK(st.st_mode)) {
|
||||
ssize_t sz;
|
||||
static char target[PATH_MAX];
|
||||
sz = readlink(path, target, sizeof(target));
|
||||
if (sz < 0)
|
||||
warning("Cannot readlink %s", path);
|
||||
else if (target[0] != '/')
|
||||
warning("Cannot lock target of relative symlink %s", path);
|
||||
else
|
||||
path = target;
|
||||
}
|
||||
sprintf(lk->filename, "%s.lock", path);
|
||||
if (strlen(path) >= sizeof(lk->filename)) return -1;
|
||||
strcpy(lk->filename, path);
|
||||
/*
|
||||
* subtract 5 from size to make sure there's room for adding
|
||||
* ".lock" for the lock file name
|
||||
*/
|
||||
resolve_symlink(lk->filename, sizeof(lk->filename)-5);
|
||||
strcat(lk->filename, ".lock");
|
||||
lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||
if (0 <= lk->fd) {
|
||||
if (!lock_file_list) {
|
||||
|
||||
65
path.c
65
path.c
@@ -304,3 +304,68 @@ int adjust_shared_perm(const char *path)
|
||||
return -2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We allow "recursive" symbolic links. Only within reason, though. */
|
||||
#define MAXDEPTH 5
|
||||
|
||||
const char *make_absolute_path(const char *path)
|
||||
{
|
||||
static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
|
||||
char cwd[1024] = "";
|
||||
int buf_index = 1, len;
|
||||
|
||||
int depth = MAXDEPTH;
|
||||
char *last_elem = NULL;
|
||||
struct stat st;
|
||||
|
||||
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
|
||||
die ("Too long path: %.*s", 60, path);
|
||||
|
||||
while (depth--) {
|
||||
if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
|
||||
char *last_slash = strrchr(buf, '/');
|
||||
if (last_slash) {
|
||||
*last_slash = '\0';
|
||||
last_elem = xstrdup(last_slash + 1);
|
||||
} else
|
||||
last_elem = xstrdup(buf);
|
||||
}
|
||||
|
||||
if (*buf) {
|
||||
if (!*cwd && !getcwd(cwd, sizeof(cwd)))
|
||||
die ("Could not get current working directory");
|
||||
|
||||
if (chdir(buf))
|
||||
die ("Could not switch to '%s'", buf);
|
||||
}
|
||||
if (!getcwd(buf, PATH_MAX))
|
||||
die ("Could not get current working directory");
|
||||
|
||||
if (last_elem) {
|
||||
int len = strlen(buf);
|
||||
if (len + strlen(last_elem) + 2 > PATH_MAX)
|
||||
die ("Too long path name: '%s/%s'",
|
||||
buf, last_elem);
|
||||
buf[len] = '/';
|
||||
strcpy(buf + len + 1, last_elem);
|
||||
free(last_elem);
|
||||
last_elem = NULL;
|
||||
}
|
||||
|
||||
if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
|
||||
len = readlink(buf, next_buf, PATH_MAX);
|
||||
if (len < 0)
|
||||
die ("Invalid symlink: %s", buf);
|
||||
next_buf[len] = '\0';
|
||||
buf = next_buf;
|
||||
buf_index = 1 - buf_index;
|
||||
next_buf = bufs[buf_index];
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cwd && chdir(cwd))
|
||||
die ("Could not change back to '%s'", cwd);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
11
read-cache.c
11
read-cache.c
@@ -380,7 +380,7 @@ static int index_name_pos_also_unmerged(struct index_state *istate,
|
||||
|
||||
int add_file_to_index(struct index_state *istate, const char *path, int verbose)
|
||||
{
|
||||
int size, namelen;
|
||||
int size, namelen, pos;
|
||||
struct stat st;
|
||||
struct cache_entry *ce;
|
||||
|
||||
@@ -414,6 +414,15 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
|
||||
ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
|
||||
}
|
||||
|
||||
pos = index_name_pos(istate, ce->name, namelen);
|
||||
if (0 <= pos &&
|
||||
!ce_stage(istate->cache[pos]) &&
|
||||
!ie_modified(istate, istate->cache[pos], &st, 1)) {
|
||||
/* Nothing changed, really */
|
||||
free(ce);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (index_path(ce->sha1, path, &st, 1))
|
||||
die("unable to index file %s", path);
|
||||
if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
|
||||
|
||||
44
refs.c
44
refs.c
@@ -1045,6 +1045,32 @@ void unlock_ref(struct ref_lock *lock)
|
||||
free(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy the reflog message msg to buf, which has been allocated sufficiently
|
||||
* large, while cleaning up the whitespaces. Especially, convert LF to space,
|
||||
* because reflog file is one line per entry.
|
||||
*/
|
||||
static int copy_msg(char *buf, const char *msg)
|
||||
{
|
||||
char *cp = buf;
|
||||
char c;
|
||||
int wasspace = 1;
|
||||
|
||||
*cp++ = '\t';
|
||||
while ((c = *msg++)) {
|
||||
if (wasspace && isspace(c))
|
||||
continue;
|
||||
wasspace = isspace(c);
|
||||
if (wasspace)
|
||||
c = ' ';
|
||||
*cp++ = c;
|
||||
}
|
||||
while (buf < cp && isspace(cp[-1]))
|
||||
cp--;
|
||||
*cp++ = '\n';
|
||||
return cp - buf;
|
||||
}
|
||||
|
||||
static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
|
||||
const unsigned char *new_sha1, const char *msg)
|
||||
{
|
||||
@@ -1098,21 +1124,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
|
||||
|
||||
adjust_shared_perm(log_file);
|
||||
|
||||
msglen = 0;
|
||||
if (msg) {
|
||||
/* clean up the message and make sure it is a single line */
|
||||
for ( ; *msg; msg++)
|
||||
if (!isspace(*msg))
|
||||
break;
|
||||
if (*msg) {
|
||||
const char *ep = strchr(msg, '\n');
|
||||
if (ep)
|
||||
msglen = ep - msg;
|
||||
else
|
||||
msglen = strlen(msg);
|
||||
}
|
||||
}
|
||||
|
||||
msglen = msg ? strlen(msg) : 0;
|
||||
committer = git_committer_info(-1);
|
||||
maxlen = strlen(committer) + msglen + 100;
|
||||
logrec = xmalloc(maxlen);
|
||||
@@ -1121,7 +1133,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
|
||||
sha1_to_hex(new_sha1),
|
||||
committer);
|
||||
if (msglen)
|
||||
len += sprintf(logrec + len - 1, "\t%.*s\n", msglen, msg) - 1;
|
||||
len += copy_msg(logrec + len - 1, msg) - 1;
|
||||
written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
|
||||
free(logrec);
|
||||
if (close(logfd) != 0 || written != len)
|
||||
|
||||
301
setup.c
301
setup.c
@@ -1,4 +1,8 @@
|
||||
#include "cache.h"
|
||||
#include "dir.h"
|
||||
|
||||
static int inside_git_dir = -1;
|
||||
static int inside_work_tree = -1;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
static inline int is_dir_sep(char c) { return c == '/' || c == '\\'; }
|
||||
@@ -207,105 +211,96 @@ static int is_git_directory(const char *suspect)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int inside_git_dir = -1;
|
||||
|
||||
int is_inside_git_dir(void)
|
||||
{
|
||||
if (inside_git_dir >= 0)
|
||||
return inside_git_dir;
|
||||
die("BUG: is_inside_git_dir called before setup_git_directory");
|
||||
if (inside_git_dir < 0)
|
||||
inside_git_dir = is_inside_dir(get_git_dir());
|
||||
return inside_git_dir;
|
||||
}
|
||||
|
||||
static int inside_work_tree = -1;
|
||||
|
||||
int is_inside_work_tree(void)
|
||||
{
|
||||
if (inside_git_dir >= 0)
|
||||
return inside_work_tree;
|
||||
die("BUG: is_inside_work_tree called before setup_git_directory");
|
||||
if (inside_work_tree < 0)
|
||||
inside_work_tree = is_inside_dir(get_git_work_tree());
|
||||
return inside_work_tree;
|
||||
}
|
||||
|
||||
static char *gitworktree_config;
|
||||
|
||||
static int git_setup_config(const char *var, const char *value)
|
||||
/*
|
||||
* If no worktree was given, and we are outside of a default work tree,
|
||||
* now is the time to set it.
|
||||
*
|
||||
* In other words, if the user calls git with something like
|
||||
*
|
||||
* git --git-dir=/some/where/else/.git bla
|
||||
*
|
||||
* default to /some/where/else as working directory; if the specified
|
||||
* git-dir does not end in "/.git", the cwd is used as working directory.
|
||||
*/
|
||||
const char *set_work_tree(const char *dir)
|
||||
{
|
||||
if (!strcmp(var, "core.worktree")) {
|
||||
if (gitworktree_config)
|
||||
strlcpy(gitworktree_config, value, PATH_MAX);
|
||||
return 0;
|
||||
char dir_buffer[PATH_MAX], *rel = NULL;
|
||||
static char buffer[PATH_MAX + 1];
|
||||
int len, suffix_len = strlen(DEFAULT_GIT_DIR_ENVIRONMENT) + 1;
|
||||
|
||||
/* strip the variable 'dir' of the postfix "/.git" if it has it */
|
||||
len = strlen(dir);
|
||||
if (len > suffix_len &&
|
||||
!strcmp(dir + len - suffix_len, "/" DEFAULT_GIT_DIR_ENVIRONMENT)) {
|
||||
if ((len - suffix_len) >= sizeof(dir_buffer))
|
||||
die("directory name too long");
|
||||
memcpy(dir_buffer, dir, len - suffix_len);
|
||||
dir_buffer[len - suffix_len] = '\0';
|
||||
|
||||
/* are we inside the default work tree? */
|
||||
rel = get_relative_cwd(buffer, sizeof(buffer), dir_buffer);
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
|
||||
/* if rel is set, the cwd is _not_ the current working tree */
|
||||
if (rel && *rel) {
|
||||
if (!is_absolute_path(dir))
|
||||
set_git_dir(make_absolute_path(dir));
|
||||
dir = dir_buffer;
|
||||
if (chdir(dir))
|
||||
die("cannot chdir to %s: %s", dir, strerror(errno));
|
||||
else
|
||||
strcat(rel, "/");
|
||||
inside_git_dir = 0;
|
||||
} else {
|
||||
rel = NULL;
|
||||
dir = getcwd(buffer, sizeof(buffer));
|
||||
}
|
||||
git_work_tree_cfg = xstrdup(dir);
|
||||
inside_work_tree = 1;
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot decide in this function whether we are in the work tree or
|
||||
* not, since the config can only be read _after_ this function was called.
|
||||
*/
|
||||
const char *setup_git_directory_gently(int *nongit_ok)
|
||||
{
|
||||
const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||
static char cwd[PATH_MAX+1];
|
||||
char worktree[PATH_MAX+1], gitdir[PATH_MAX+1];
|
||||
const char *gitdirenv, *gitworktree;
|
||||
int wt_rel_gitdir = 0;
|
||||
const char *gitdirenv;
|
||||
int len, offset;
|
||||
int minoffset = 0;
|
||||
|
||||
/*
|
||||
* If GIT_DIR is set explicitly, we're not going
|
||||
* to do any discovery, but we still do repository
|
||||
* validation.
|
||||
*/
|
||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!gitdirenv) {
|
||||
int len, offset;
|
||||
int minoffset = 0;
|
||||
|
||||
if (!getcwd(cwd, sizeof(cwd)-1))
|
||||
die("Unable to read current working directory");
|
||||
#ifdef __MINGW32__
|
||||
if (cwd[1] == ':')
|
||||
minoffset = 2;
|
||||
#endif
|
||||
|
||||
offset = len = strlen(cwd);
|
||||
for (;;) {
|
||||
if (is_git_directory(".git"))
|
||||
break;
|
||||
if (offset == 0) {
|
||||
offset = -1;
|
||||
break;
|
||||
}
|
||||
chdir("..");
|
||||
while (offset > minoffset && cwd[--offset] != '/')
|
||||
; /* do nothing */
|
||||
}
|
||||
|
||||
if (offset >= 0) {
|
||||
inside_work_tree = 1;
|
||||
git_config(git_default_config);
|
||||
if (offset == len) {
|
||||
inside_git_dir = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cwd[len++] = '/';
|
||||
cwd[len] = '\0';
|
||||
inside_git_dir = !prefixcmp(cwd + offset + 1, ".git/");
|
||||
return cwd + offset + 1;
|
||||
}
|
||||
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
if (!is_git_directory(".")) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("Not a git repository");
|
||||
}
|
||||
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
|
||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!gitdirenv)
|
||||
die("getenv after setenv failed");
|
||||
}
|
||||
|
||||
if (PATH_MAX - 40 < strlen(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
if (gitdirenv) {
|
||||
if (PATH_MAX - 40 < strlen(gitdirenv))
|
||||
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
|
||||
if (is_git_directory(gitdirenv)) {
|
||||
if (!work_tree_env)
|
||||
return set_work_tree(gitdirenv);
|
||||
return NULL;
|
||||
}
|
||||
die("$%s too big", GIT_DIR_ENVIRONMENT);
|
||||
}
|
||||
if (!is_git_directory(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
@@ -315,92 +310,57 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
|
||||
if (!getcwd(cwd, sizeof(cwd)-1))
|
||||
die("Unable to read current working directory");
|
||||
if (chdir(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("Cannot change directory to $%s '%s'",
|
||||
GIT_DIR_ENVIRONMENT, gitdirenv);
|
||||
}
|
||||
if (!getcwd(gitdir, sizeof(gitdir)-1))
|
||||
die("Unable to read current working directory");
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
#ifdef __MINGW32__
|
||||
if (cwd[1] == ':')
|
||||
minoffset = 2;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In case there is a work tree we may change the directory,
|
||||
* therefore make GIT_DIR an absolute path.
|
||||
* Test in the following order (relative to the cwd):
|
||||
* - .git/
|
||||
* - ./ (bare)
|
||||
* - ../.git/
|
||||
* - ../ (bare)
|
||||
* - ../../.git/
|
||||
* etc.
|
||||
*/
|
||||
if (gitdirenv[0] != '/') {
|
||||
setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
|
||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!gitdirenv)
|
||||
die("getenv after setenv failed");
|
||||
if (PATH_MAX - 40 < strlen(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("$%s too big after expansion to absolute path",
|
||||
GIT_DIR_ENVIRONMENT);
|
||||
}
|
||||
}
|
||||
|
||||
strcat(cwd, "/");
|
||||
strcat(gitdir, "/");
|
||||
inside_git_dir = !prefixcmp(cwd, gitdir);
|
||||
|
||||
gitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||
if (!gitworktree) {
|
||||
gitworktree_config = worktree;
|
||||
worktree[0] = '\0';
|
||||
}
|
||||
git_config(git_setup_config);
|
||||
if (!gitworktree) {
|
||||
gitworktree_config = NULL;
|
||||
if (worktree[0])
|
||||
gitworktree = worktree;
|
||||
if (gitworktree && gitworktree[0] != '/')
|
||||
wt_rel_gitdir = 1;
|
||||
}
|
||||
|
||||
if (wt_rel_gitdir && chdir(gitdirenv))
|
||||
die("Cannot change directory to $%s '%s'",
|
||||
GIT_DIR_ENVIRONMENT, gitdirenv);
|
||||
if (gitworktree && chdir(gitworktree)) {
|
||||
if (nongit_ok) {
|
||||
if (wt_rel_gitdir && chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
*nongit_ok = 1;
|
||||
offset = len = strlen(cwd);
|
||||
for (;;) {
|
||||
if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
|
||||
break;
|
||||
if (is_git_directory(".")) {
|
||||
inside_git_dir = 1;
|
||||
if (!work_tree_env)
|
||||
inside_work_tree = 0;
|
||||
setenv(GIT_DIR_ENVIRONMENT, ".", 1);
|
||||
return NULL;
|
||||
}
|
||||
if (wt_rel_gitdir)
|
||||
die("Cannot change directory to working tree '%s'"
|
||||
" from $%s", gitworktree, GIT_DIR_ENVIRONMENT);
|
||||
else
|
||||
die("Cannot change directory to working tree '%s'",
|
||||
gitworktree);
|
||||
}
|
||||
if (!getcwd(worktree, sizeof(worktree)-1))
|
||||
die("Unable to read current working directory");
|
||||
strcat(worktree, "/");
|
||||
inside_work_tree = !prefixcmp(cwd, worktree);
|
||||
|
||||
if (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&
|
||||
strcmp(worktree, gitdir)) {
|
||||
inside_git_dir = 0;
|
||||
chdir("..");
|
||||
do {
|
||||
if (!offset) {
|
||||
if (nongit_ok) {
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("Not a git repository");
|
||||
}
|
||||
} while (offset > minoffset && cwd[--offset] != '/');
|
||||
}
|
||||
|
||||
if (!inside_work_tree) {
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
inside_git_dir = 0;
|
||||
if (!work_tree_env)
|
||||
inside_work_tree = 1;
|
||||
git_work_tree_cfg = xstrndup(cwd, offset);
|
||||
if (offset == len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strcmp(cwd, worktree))
|
||||
return NULL;
|
||||
return cwd+strlen(worktree);
|
||||
/* Make "offset" point to past the '/', and add a '/' at the end */
|
||||
offset++;
|
||||
cwd[len++] = '/';
|
||||
cwd[len] = 0;
|
||||
return cwd + offset;
|
||||
}
|
||||
|
||||
int git_config_perm(const char *var, const char *value)
|
||||
@@ -424,11 +384,21 @@ int git_config_perm(const char *var, const char *value)
|
||||
|
||||
int check_repository_format_version(const char *var, const char *value)
|
||||
{
|
||||
if (strcmp(var, "core.repositoryformatversion") == 0)
|
||||
repository_format_version = git_config_int(var, value);
|
||||
if (strcmp(var, "core.repositoryformatversion") == 0)
|
||||
repository_format_version = git_config_int(var, value);
|
||||
else if (strcmp(var, "core.sharedrepository") == 0)
|
||||
shared_repository = git_config_perm(var, value);
|
||||
return 0;
|
||||
else if (strcmp(var, "core.bare") == 0) {
|
||||
is_bare_repository_cfg = git_config_bool(var, value);
|
||||
if (is_bare_repository_cfg == 1)
|
||||
inside_work_tree = -1;
|
||||
} else if (strcmp(var, "core.worktree") == 0) {
|
||||
if (git_work_tree_cfg)
|
||||
free(git_work_tree_cfg);
|
||||
git_work_tree_cfg = xstrdup(value);
|
||||
inside_work_tree = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_repository_format(void)
|
||||
@@ -444,5 +414,16 @@ const char *setup_git_directory(void)
|
||||
{
|
||||
const char *retval = setup_git_directory_gently(NULL);
|
||||
check_repository_format();
|
||||
|
||||
/* If the work tree is not the default one, recompute prefix */
|
||||
if (inside_work_tree < 0) {
|
||||
static char buffer[PATH_MAX + 1];
|
||||
char *rel;
|
||||
if (retval && chdir(retval))
|
||||
die ("Could not jump back into original cwd");
|
||||
rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
|
||||
return rel && *rel ? strcat(rel, "/") : NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -305,4 +305,20 @@ test_expect_success 'update-index D/F conflict' '
|
||||
test $numpath0 = 1
|
||||
'
|
||||
|
||||
test_expect_success 'absolute path works as expected' '
|
||||
mkdir first &&
|
||||
ln -s ../.git first/.git &&
|
||||
mkdir second &&
|
||||
ln -s ../first second/other &&
|
||||
mkdir third &&
|
||||
dir="$(cd .git; pwd -P)" &&
|
||||
dir2=third/../second/other/.git &&
|
||||
test "$dir" = "$(test-absolute-path $dir2)" &&
|
||||
file="$dir"/index &&
|
||||
test "$file" = "$(test-absolute-path $dir2/index)" &&
|
||||
ln -s ../first/file .git/syml &&
|
||||
sym="$(cd first; pwd -P)"/file &&
|
||||
test "$sym" = "$(test-absolute-path $dir2/syml)"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -325,6 +325,9 @@ EOF
|
||||
|
||||
test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
|
||||
|
||||
test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \
|
||||
'git config --file non-existing-config -l; test $? != 0'
|
||||
|
||||
cat > other-config << EOF
|
||||
[ein]
|
||||
bahn = strasse
|
||||
@@ -338,6 +341,9 @@ GIT_CONFIG=other-config git config -l > output
|
||||
|
||||
test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
|
||||
|
||||
test_expect_success 'alternative GIT_CONFIG (--file)' \
|
||||
'git config --file other-config -l > output && cmp output expect'
|
||||
|
||||
GIT_CONFIG=other-config git config anwohner.park ausweis
|
||||
|
||||
cat > expect << EOF
|
||||
@@ -595,4 +601,19 @@ echo >>result
|
||||
|
||||
test_expect_success '--null --get-regexp' 'cmp result expect'
|
||||
|
||||
test_expect_success 'symlinked configuration' '
|
||||
|
||||
ln -s notyet myconfig &&
|
||||
GIT_CONFIG=myconfig git config test.frotz nitfol &&
|
||||
test -h myconfig &&
|
||||
test -f notyet &&
|
||||
test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol &&
|
||||
GIT_CONFIG=myconfig git config test.xyzzy rezrov &&
|
||||
test -h myconfig &&
|
||||
test -f notyet &&
|
||||
test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol &&
|
||||
test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -31,9 +31,9 @@ test_rev_parse() {
|
||||
test_rev_parse toplevel false false true ''
|
||||
|
||||
cd .git || exit 1
|
||||
test_rev_parse .git/ false true true .git/
|
||||
test_rev_parse .git/ true true false ''
|
||||
cd objects || exit 1
|
||||
test_rev_parse .git/objects/ false true true .git/objects/
|
||||
test_rev_parse .git/objects/ true true false ''
|
||||
cd ../.. || exit 1
|
||||
|
||||
mkdir -p sub/dir || exit 1
|
||||
@@ -42,7 +42,7 @@ test_rev_parse subdirectory false false true sub/dir/
|
||||
cd ../.. || exit 1
|
||||
|
||||
git config core.bare true
|
||||
test_rev_parse 'core.bare = true' true false true
|
||||
test_rev_parse 'core.bare = true' true false false
|
||||
|
||||
git config --unset core.bare
|
||||
test_rev_parse 'core.bare undefined' false false true
|
||||
@@ -50,28 +50,28 @@ test_rev_parse 'core.bare undefined' false false true
|
||||
mkdir work || exit 1
|
||||
cd work || exit 1
|
||||
export GIT_DIR=../.git
|
||||
export GIT_CONFIG="$GIT_DIR"/config
|
||||
export GIT_CONFIG="$(pwd)"/../.git/config
|
||||
|
||||
git config core.bare false
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true work/
|
||||
|
||||
git config core.bare true
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false true ''
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false false ''
|
||||
|
||||
git config --unset core.bare
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
|
||||
test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true work/
|
||||
|
||||
mv ../.git ../repo.git || exit 1
|
||||
export GIT_DIR=../repo.git
|
||||
export GIT_CONFIG="$GIT_DIR"/config
|
||||
export GIT_CONFIG="$(pwd)"/../repo.git/config
|
||||
|
||||
git config core.bare false
|
||||
test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''
|
||||
|
||||
git config core.bare true
|
||||
test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''
|
||||
test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false false ''
|
||||
|
||||
git config --unset core.bare
|
||||
test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''
|
||||
test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' false false true ''
|
||||
|
||||
test_done
|
||||
|
||||
@@ -33,17 +33,17 @@ mv .git repo.git || exit 1
|
||||
|
||||
say "core.worktree = relative path"
|
||||
export GIT_DIR=repo.git
|
||||
export GIT_CONFIG=$GIT_DIR/config
|
||||
export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
|
||||
unset GIT_WORK_TREE
|
||||
git config core.worktree ../work
|
||||
test_rev_parse 'outside' false false false
|
||||
cd work || exit 1
|
||||
export GIT_DIR=../repo.git
|
||||
export GIT_CONFIG=$GIT_DIR/config
|
||||
export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
|
||||
test_rev_parse 'inside' false false true ''
|
||||
cd sub/dir || exit 1
|
||||
export GIT_DIR=../../../repo.git
|
||||
export GIT_CONFIG=$GIT_DIR/config
|
||||
export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
|
||||
test_rev_parse 'subdirectory' false false true sub/dir/
|
||||
cd ../../.. || exit 1
|
||||
|
||||
@@ -84,9 +84,23 @@ test_rev_parse 'in repo.git' false true false
|
||||
cd objects || exit 1
|
||||
test_rev_parse 'in repo.git/objects' false true false
|
||||
cd ../work || exit 1
|
||||
test_rev_parse 'in repo.git/work' false false true ''
|
||||
test_rev_parse 'in repo.git/work' false true true ''
|
||||
cd sub/dir || exit 1
|
||||
test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/
|
||||
test_rev_parse 'in repo.git/sub/dir' false true true sub/dir/
|
||||
cd ../../../.. || exit 1
|
||||
|
||||
test_expect_success 'repo finds its work tree' '
|
||||
(cd repo.git &&
|
||||
: > work/sub/dir/untracked &&
|
||||
test sub/dir/untracked = "$(git ls-files --others)")
|
||||
'
|
||||
|
||||
test_expect_success 'repo finds its work tree from work tree, too' '
|
||||
(cd repo.git/work/sub/dir &&
|
||||
: > tracked &&
|
||||
git --git-dir=../../.. add tracked &&
|
||||
cd ../../.. &&
|
||||
test sub/dir/tracked = "$(git ls-files)")
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -68,6 +68,9 @@ test "\$1" = .git/COMMIT_EDITMSG && {
|
||||
test -z "\$FAKE_COMMIT_AMEND" || echo "\$FAKE_COMMIT_AMEND" >> "\$1"
|
||||
exit
|
||||
}
|
||||
test -z "\$EXPECT_COUNT" ||
|
||||
test "\$EXPECT_COUNT" = \$(grep -ve "^#" -e "^$" < "\$1" | wc -l) ||
|
||||
exit
|
||||
test -z "\$FAKE_LINES" && exit
|
||||
grep -v "^#" < "\$1" > "\$1".tmp
|
||||
rm "\$1"
|
||||
@@ -95,6 +98,14 @@ test_expect_success 'no changes are a nop' '
|
||||
test $(git rev-parse I) = $(git rev-parse HEAD)
|
||||
'
|
||||
|
||||
test_expect_success 'test the [branch] option' '
|
||||
git checkout -b dead-end &&
|
||||
git rm file6 &&
|
||||
git commit -m "stop here" &&
|
||||
git rebase -i F branch2 &&
|
||||
test $(git rev-parse I) = $(git rev-parse HEAD)
|
||||
'
|
||||
|
||||
test_expect_success 'rebase on top of a non-conflicting commit' '
|
||||
git checkout branch1 &&
|
||||
git tag original-branch1 &&
|
||||
@@ -251,4 +262,16 @@ test_expect_success 'interrupted squash works as expected' '
|
||||
test $one = $(git rev-parse HEAD~2)
|
||||
'
|
||||
|
||||
test_expect_success 'ignore patch if in upstream' '
|
||||
HEAD=$(git rev-parse HEAD) &&
|
||||
git checkout -b has-cherry-picked HEAD^ &&
|
||||
echo unrelated > file7 &&
|
||||
git add file7 &&
|
||||
test_tick &&
|
||||
git commit -m "unrelated change" &&
|
||||
git cherry-pick $HEAD &&
|
||||
EXPECT_COUNT=1 git rebase -i $HEAD &&
|
||||
test $HEAD = $(git rev-parse HEAD^)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
48
t/t3405-rebase-malformed.sh
Executable file
48
t/t3405-rebase-malformed.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='rebase should not insist on git message convention'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
cat >F <<\EOF
|
||||
This is an example of a commit log message
|
||||
that does not conform to git commit convention.
|
||||
|
||||
It has two paragraphs, but its first paragraph is not friendly
|
||||
to oneline summary format.
|
||||
EOF
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
>file1 &&
|
||||
>file2 &&
|
||||
git add file1 file2 &&
|
||||
test_tick &&
|
||||
git commit -m "Initial commit" &&
|
||||
|
||||
git checkout -b side &&
|
||||
cat F >file2 &&
|
||||
git add file2 &&
|
||||
test_tick &&
|
||||
git commit -F F &&
|
||||
|
||||
git cat-file commit HEAD | sed -e "1,/^\$/d" >F0 &&
|
||||
|
||||
git checkout master &&
|
||||
|
||||
echo One >file1 &&
|
||||
test_tick &&
|
||||
git add file1 &&
|
||||
git commit -m "Second commit"
|
||||
'
|
||||
|
||||
test_expect_success rebase '
|
||||
|
||||
git rebase master side &&
|
||||
git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 &&
|
||||
|
||||
diff -u F0 F1 &&
|
||||
diff -u F F0
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -135,8 +135,8 @@ test_expect_success 'git add with filemode=0, symlinks=0 prefers stage 2 over st
|
||||
(
|
||||
echo "100644 $(git hash-object -w stage1) 1 file"
|
||||
echo "100755 $(git hash-object -w stage2) 2 file"
|
||||
echo "100644 $(printf $s | git hash-object -w -t blob --stdin) 1 symlink"
|
||||
echo "120000 $(printf $s | git hash-object -w -t blob --stdin) 2 symlink"
|
||||
echo "100644 $(printf 1 | git hash-object -w -t blob --stdin) 1 symlink"
|
||||
echo "120000 $(printf 2 | git hash-object -w -t blob --stdin) 2 symlink"
|
||||
) | git update-index --index-info &&
|
||||
git config core.filemode 0 &&
|
||||
git config core.symlinks 0 &&
|
||||
|
||||
134
t/t7501-commit.sh
Normal file
134
t/t7501-commit.sh
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
|
||||
#
|
||||
|
||||
# FIXME: Test the various index usages, -i and -o, test reflog,
|
||||
# signoff, hooks
|
||||
|
||||
test_description='git-commit'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_tick
|
||||
|
||||
test_expect_success \
|
||||
"initial status" \
|
||||
"echo 'bongo bongo' >file &&
|
||||
git-add file && \
|
||||
git-status | grep 'Initial commit'"
|
||||
|
||||
test_expect_failure \
|
||||
"fail initial amend" \
|
||||
"git-commit --amend"
|
||||
|
||||
test_expect_success \
|
||||
"initial commit" \
|
||||
"git-commit -m initial"
|
||||
|
||||
test_expect_failure \
|
||||
"invalid options 1" \
|
||||
"git-commit -m foo -m bar -F file"
|
||||
|
||||
test_expect_failure \
|
||||
"invalid options 2" \
|
||||
"git-commit -C HEAD -m illegal"
|
||||
|
||||
test_expect_failure \
|
||||
"using invalid commit with -C" \
|
||||
"git-commit -C bogus"
|
||||
|
||||
test_expect_failure \
|
||||
"testing nothing to commit" \
|
||||
"git-commit -m initial"
|
||||
|
||||
test_expect_success \
|
||||
"next commit" \
|
||||
"echo 'bongo bongo bongo' >file \
|
||||
git-commit -m next -a"
|
||||
|
||||
test_expect_failure \
|
||||
"commit message from non-existing file" \
|
||||
"echo 'more bongo: bongo bongo bongo bongo' >file && \
|
||||
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 \
|
||||
"empty commit message" \
|
||||
"git-commit -F msg -a"
|
||||
|
||||
test_expect_success \
|
||||
"commit message from file" \
|
||||
"echo 'this is the commit message, coming from a file' >msg && \
|
||||
git-commit -F msg -a"
|
||||
|
||||
cat >editor <<\EOF
|
||||
#!/bin/sh
|
||||
sed -i -e "s/a file/an amend commit/g" $1
|
||||
EOF
|
||||
chmod 755 editor
|
||||
|
||||
test_expect_success \
|
||||
"amend commit" \
|
||||
"VISUAL=./editor git-commit --amend"
|
||||
|
||||
test_expect_failure \
|
||||
"passing -m and -F" \
|
||||
"echo 'enough with the bongos' >file && \
|
||||
git-commit -F msg -m amending ."
|
||||
|
||||
test_expect_success \
|
||||
"using message from other commit" \
|
||||
"git-commit -C HEAD^ ."
|
||||
|
||||
cat >editor <<\EOF
|
||||
#!/bin/sh
|
||||
sed -i -e "s/amend/older/g" $1
|
||||
EOF
|
||||
chmod 755 editor
|
||||
|
||||
test_expect_success \
|
||||
"editing message from other commit" \
|
||||
"echo 'hula hula' >file && \
|
||||
VISUAL=./editor git-commit -c HEAD^ -a"
|
||||
|
||||
test_expect_success \
|
||||
"message from stdin" \
|
||||
"echo 'silly new contents' >file && \
|
||||
echo commit message from stdin | git-commit -F - -a"
|
||||
|
||||
test_expect_success \
|
||||
"overriding author from command line" \
|
||||
"echo 'gak' >file && \
|
||||
git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a"
|
||||
|
||||
test_expect_success \
|
||||
"interactive add" \
|
||||
"echo 7 | git-commit --interactive | grep 'What now'"
|
||||
|
||||
test_expect_success \
|
||||
"showing committed revisions" \
|
||||
"git-rev-list HEAD >current"
|
||||
|
||||
# We could just check the head sha1, but checking each commit makes it
|
||||
# easier to isolate bugs.
|
||||
|
||||
cat >expected <<\EOF
|
||||
72c0dc9855b0c9dadcbfd5a31cab072e0cb774ca
|
||||
9b88fc14ce6b32e3d9ee021531a54f18a5cf38a2
|
||||
3536bbb352c3a1ef9a420f5b4242d48578b92aa7
|
||||
d381ac431806e53f3dd7ac2f1ae0534f36d738b9
|
||||
4fd44095ad6334f3ef72e4c5ec8ddf108174b54a
|
||||
402702b49136e7587daa9280e91e4bb7cb2179f7
|
||||
EOF
|
||||
|
||||
test_expect_success \
|
||||
'validate git-rev-list output.' \
|
||||
'diff current expected'
|
||||
|
||||
test_done
|
||||
@@ -11,6 +11,7 @@ TZ=UTC
|
||||
export LANG LC_ALL PAGER TZ
|
||||
EDITOR=:
|
||||
VISUAL=:
|
||||
unset GIT_EDITOR
|
||||
unset AUTHOR_DATE
|
||||
unset AUTHOR_EMAIL
|
||||
unset AUTHOR_NAME
|
||||
|
||||
11
test-absolute-path.c
Normal file
11
test-absolute-path.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "cache.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
while (argc > 1) {
|
||||
puts(make_absolute_path(argv[1]));
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user