aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-12-19 01:38:18 -0800
committerJunio C Hamano <junkio@cox.net>2006-12-19 01:38:18 -0800
commit5fed4668153c9ca6e44ec84a0976089f515705aa (patch)
tree82f3ce0d2ea76ca31cebd3a5b40d0993e019859a
parent63085fabbdeaad9eb8b29d39d0998c704e6cd232 (diff)
parent8683a45d66967b0969516a2b72cdbf136c2064a2 (diff)
downloadgit-5fed4668153c9ca6e44ec84a0976089f515705aa.tar.gz
git-5fed4668153c9ca6e44ec84a0976089f515705aa.tar.xz
Merge branch 'jc/test-clone' into jc/clone
* jc/test-clone: (35 commits) Introduce GIT_TEMPLATE_DIR Revert "fix testsuite: make sure they use templates freshly built from the source" fix testsuite: make sure they use templates freshly built from the source rerere: fix breakage of resolving. Add config example with respect to branch Add documentation for show-branch --topics make git a bit less cryptic on fetch errors make patch_delta() error cases a bit more verbose racy-git: documentation updates. show-ref: fix --exclude-existing parse-remote::expand_refs_wildcard() vim syntax: follow recent changes to commit template show-ref: fix --verify --hash=length show-ref: fix --quiet --verify avoid accessing _all_ loose refs in git-show-ref --verify git-fetch: Avoid reading packed refs over and over again Teach show-branch how to show ref-log data. markup fix in svnimport documentation. Documentation: new option -P for git-svnimport Fix mis-mark-up in git-merge-file.txt documentation ...
-rw-r--r--Documentation/config.txt5
-rw-r--r--Documentation/git-merge-file.txt4
-rw-r--r--Documentation/git-show-branch.txt10
-rw-r--r--Documentation/git-svnimport.txt13
-rw-r--r--Documentation/technical/racy-git.txt38
-rw-r--r--Makefile4
-rw-r--r--builtin-blame.c15
-rw-r--r--builtin-init-db.c7
-rw-r--r--builtin-repo-config.c14
-rw-r--r--builtin-show-branch.c35
-rw-r--r--builtin-show-ref.c99
-rw-r--r--cache.h2
-rw-r--r--config.c64
-rw-r--r--contrib/vim/syntax/gitcommit.vim4
-rwxr-xr-xgit-fetch.sh14
-rwxr-xr-xgit-ls-remote.sh2
-rwxr-xr-xgit-parse-remote.sh8
-rwxr-xr-xgit-rerere.perl2
-rwxr-xr-xgitweb/gitweb.perl216
-rw-r--r--ident.c15
-rw-r--r--patch-delta.c13
-rw-r--r--pkt-line.c2
-rw-r--r--read-cache.c6
-rw-r--r--receive-pack.c2
-rw-r--r--refs.c10
-rwxr-xr-xt/t0000-basic.sh9
-rwxr-xr-xt/t1300-repo-config.sh48
-rwxr-xr-xt/t3200-branch.sh6
-rwxr-xr-xt/test-lib.sh3
29 files changed, 564 insertions, 106 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ceac54b02..22482d6a9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -31,6 +31,11 @@ Example
external = "/usr/local/bin/gnu-diff -u"
renames = true
+ [branch "devel"]
+ remote = origin
+ merge = refs/heads/devel
+
+
Variables
~~~~~~~~~
diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt
index 0b41d66a7..29d3faa55 100644
--- a/Documentation/git-merge-file.txt
+++ b/Documentation/git-merge-file.txt
@@ -1,9 +1,9 @@
git-merge-file(1)
-============
+=================
NAME
----
-git-merge-file - threeway file merge
+git-merge-file - three-way file merge
SYNOPSIS
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index a2445a48f..948ff10e6 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base]
- [--no-name | --sha1-name] [<rev> | <glob>]...
+ [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
DESCRIPTION
-----------
@@ -86,6 +86,14 @@ OPTIONS
of "master"), name them with the unique prefix of their
object names.
+--topics::
+ Shows only commits that are NOT on the first branch given.
+ This helps track topic branches by hiding any commit that
+ is already in the main line of development. When given
+ "git show-branch --topics master topic1 topic2", this
+ will show the revisions given by "git rev-list {caret}master
+ topic1 topic2"
+
Note that --more, --list, --independent and --merge-base options
are mutually exclusive.
diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index b1b87c2fc..2c7c7dad5 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -15,6 +15,7 @@ SYNOPSIS
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
[ -I <ignorefile_name> ] [ -A <author_file> ]
+ [ -P <path_from_trunk> ]
<SVN_repository_URL> [ <path> ]
@@ -103,9 +104,17 @@ repository without -A.
-l <max_rev>::
Specify a maximum revision number to pull.
++
+Formerly, this option controlled how many revisions to pull,
+due to SVN memory leaks. (These have been worked around.)
- Formerly, this option controlled how many revisions to pull,
- due to SVN memory leaks. (These have been worked around.)
+-P <path_from_trunk>::
+ Partial import of the SVN tree.
++
+By default, the whole tree on the SVN trunk (/trunk) is imported.
+'-P my/proj' will import starting only from '/trunk/my/proj'.
+This option is useful when you want to import one project from a
+svn repo which hosts multiple projects under the same trunk.
-v::
Verbosity: let 'svnimport' report what it is doing.
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
index 7597d0414..5030d9f2f 100644
--- a/Documentation/technical/racy-git.txt
+++ b/Documentation/technical/racy-git.txt
@@ -4,7 +4,7 @@ Use of index and Racy git problem
Background
----------
-The index is one of the most important data structure in git.
+The index is one of the most important data structures in git.
It represents a virtual working tree state by recording list of
paths and their object names and serves as a staging area to
write out the next tree object to be committed. The state is
@@ -16,7 +16,7 @@ virtual working tree state in the index and the files in the
working tree. The most obvious case is when the user asks `git
diff` (or its low level implementation, `git diff-files`) or
`git-ls-files --modified`. In addition, git internally checks
-if the files in the working tree is different from what are
+if the files in the working tree are different from what are
recorded in the index to avoid stomping on local changes in them
during patch application, switching branches, and merging.
@@ -24,9 +24,9 @@ In order to speed up this comparison between the files in the
working tree and the index entries, the index entries record the
information obtained from the filesystem via `lstat(2)` system
call when they were last updated. When checking if they differ,
-git first runs `lstat(2)` on the files and compare the result
+git first runs `lstat(2)` on the files and compares the result
with this information (this is what was originally done by the
-`ce_match_stat()` function, which the current code does in
+`ce_match_stat()` function, but the current code does it in
`ce_match_stat_basic()` function). If some of these "cached
stat information" fields do not match, git can tell that the
files are modified without even looking at their contents.
@@ -53,8 +53,9 @@ Racy git
There is one slight problem with the optimization based on the
cached stat information. Consider this sequence:
+ : modify 'foo'
$ git update-index 'foo'
- : modify 'foo' in-place without changing its size
+ : modify 'foo' again, in-place, without changing its size
The first `update-index` computes the object name of the
contents of file `foo` and updates the index entry for `foo`
@@ -62,7 +63,8 @@ along with the `struct stat` information. If the modification
that follows it happens very fast so that the file's `st_mtime`
timestamp does not change, after this sequence, the cached stat
information the index entry records still exactly match what you
-can obtain from the filesystem, but the file `foo` is modified.
+would see in the filesystem, even though the file `foo` is now
+different.
This way, git can incorrectly think files in the working tree
are unmodified even though they actually are. This is called
the "racy git" problem (discovered by Pasky), and the entries
@@ -87,7 +89,7 @@ the stat information from updated paths, `st_mtime` timestamp of
it is usually the same as or newer than any of the paths the
index contains. And no matter how quick the modification that
follows `git update-index foo` finishes, the resulting
-`st_mtime` timestamp on `foo` cannot get the timestamp earlier
+`st_mtime` timestamp on `foo` cannot get a value earlier
than the index file. Therefore, index entries that can be
racily clean are limited to the ones that have the same
timestamp as the index file itself.
@@ -111,7 +113,7 @@ value, and falsely clean entry `foo` would not be caught by the
timestamp comparison check done with the former logic anymore.
The latter makes sure that the cached stat information for `foo`
would never match with the file in the working tree, so later
-checks by `ce_match_stat_basic()` would report the index entry
+checks by `ce_match_stat_basic()` would report that the index entry
does not match the file and git does not have to fall back on more
expensive `ce_modified_check_fs()`.
@@ -155,17 +157,16 @@ of the cached stat information.
Avoiding runtime penalty
------------------------
-In order to avoid the above runtime penalty, the recent "master"
-branch (post 1.4.2) has a code that makes sure the index file
-gets timestamp newer than the youngest files in the index when
+In order to avoid the above runtime penalty, post 1.4.2 git used
+to have a code that made sure the index file
+got timestamp newer than the youngest files in the index when
there are many young files with the same timestamp as the
resulting index file would otherwise would have by waiting
before finishing writing the index file out.
-I suspect that in practice the situation where many paths in the
-index are all racily clean is quite rare. The only code paths
-that can record recent timestamp for large number of paths I
-know of are:
+I suspected that in practice the situation where many paths in the
+index are all racily clean was quite rare. The only code paths
+that can record recent timestamp for large number of paths are:
. Initial `git add .` of a large project.
@@ -188,6 +189,7 @@ 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.
-So in summary I think we should not worry about avoiding the
-runtime penalty and get rid of the "wait before finishing
-writing" code out.
+Based on this discussion, the current code does not use the
+"workaround" to avoid the runtime penalty that does not exist in
+practice anymore. This was done with commit 0fc82cff on Aug 15,
+2006.
diff --git a/Makefile b/Makefile
index 05cfe45b1..8919dabc7 100644
--- a/Makefile
+++ b/Makefile
@@ -796,8 +796,8 @@ test: all
test-date$X: test-date.c date.o ctype.o
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
-test-delta$X: test-delta.c diff-delta.o patch-delta.o
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
+test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS)
+ $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
diff --git a/builtin-blame.c b/builtin-blame.c
index dc3ffeaff..a25072446 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1090,6 +1090,11 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
if (!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age))
pass_blame(sb, suspect, opt);
+ else {
+ commit->object.flags |= UNINTERESTING;
+ if (commit->object.parsed)
+ mark_parents_uninteresting(commit);
+ }
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
@@ -1273,6 +1278,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
printf("committer-tz %s\n", ci.committer_tz);
printf("filename %s\n", suspect->path);
printf("summary %s\n", ci.summary);
+ if (suspect->commit->object.flags & UNINTERESTING)
+ printf("boundary\n");
}
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
printf("filename %s\n", suspect->path);
@@ -1308,8 +1315,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
cp = nth_line(sb, ent->lno);
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
+ int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
+
+ if (suspect->commit->object.flags & UNINTERESTING) {
+ length--;
+ putchar('^');
+ }
- printf("%.*s", (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8, hex);
+ printf("%.*s", length, hex);
if (opt & OUTPUT_ANNOTATE_COMPAT)
printf("\t(%10s\t%10s\t%d)", ci.author,
format_time(ci.author_time, ci.author_tz,
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 1d7d15e8d..c8ed5c2a0 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -124,8 +124,11 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
int template_len;
DIR *dir;
- if (!template_dir)
- template_dir = DEFAULT_GIT_TEMPLATE_DIR;
+ if (!template_dir) {
+ template_dir = getenv("GIT_TEMPLATE_DIR");
+ if (!template_dir)
+ template_dir = DEFAULT_GIT_TEMPLATE_DIR;
+ }
strcpy(template_path, template_dir);
template_len = strlen(template_path);
if (template_path[template_len-1] != '/') {
diff --git a/builtin-repo-config.c b/builtin-repo-config.c
index 64fbdb7b2..a38099a63 100644
--- a/builtin-repo-config.c
+++ b/builtin-repo-config.c
@@ -3,7 +3,7 @@
#include <regex.h>
static const char git_config_set_usage[] =
-"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --list";
+"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list";
static char *key;
static regex_t *key_regexp;
@@ -148,6 +148,18 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
} else {
die("$HOME not set");
}
+ } else if (!strcmp(argv[1], "--rename-section")) {
+ int ret;
+ if (argc != 4)
+ usage(git_config_set_usage);
+ ret = git_config_rename_section(argv[2], argv[3]);
+ if (ret < 0)
+ return ret;
+ if (ret == 0) {
+ fprintf(stderr, "No such section!\n");
+ return 1;
+ }
+ return 0;
} else
break;
argc--;
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index fb1a4000d..a38ac34ef 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -6,7 +6,7 @@
#include "builtin.h"
static const char show_branch_usage[] =
-"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
+"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n] <branch>";
static int default_num;
static int default_alloc;
@@ -17,6 +17,8 @@ static const char **default_arg;
#define REV_SHIFT 2
#define MAX_REVS (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
+#define DEFAULT_REFLOG 4
+
static struct commit *interesting(struct commit_list *list)
{
while (list) {
@@ -570,6 +572,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int head_at = -1;
int topics = 0;
int dense = 1;
+ int reflog = 0;
git_config(git_show_branch_config);
@@ -615,6 +618,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
dense = 0;
else if (!strcmp(arg, "--date-order"))
lifo = 0;
+ else if (!strcmp(arg, "--reflog")) {
+ reflog = DEFAULT_REFLOG;
+ }
+ else if (!strncmp(arg, "--reflog=", 9)) {
+ char *end;
+ reflog = strtoul(arg + 9, &end, 10);
+ if (*end != '\0')
+ die("unrecognized reflog count '%s'", arg + 9);
+ }
else
usage(show_branch_usage);
ac--; av++;
@@ -622,7 +634,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
ac--; av++;
/* Only one of these is allowed */
- if (1 < independent + merge_base + (extra != 0))
+ if (1 < independent + merge_base + (extra != 0) + (!!reflog))
usage(show_branch_usage);
/* If nothing is specified, show all branches by default */
@@ -631,9 +643,22 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (all_heads + all_tags)
snarf_refs(all_heads, all_tags);
- while (0 < ac) {
- append_one_rev(*av);
- ac--; av++;
+ if (reflog) {
+ int reflen;
+ if (!ac)
+ die("--reflog option needs one branch name");
+ reflen = strlen(*av);
+ for (i = 0; i < reflog; i++) {
+ char *name = xmalloc(reflen + 20);
+ sprintf(name, "%s@{%d}", *av, i);
+ append_one_rev(name);
+ }
+ }
+ else {
+ while (0 < ac) {
+ append_one_rev(*av);
+ ac--; av++;
+ }
}
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index 073979855..853f13f6a 100644
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
@@ -2,13 +2,23 @@
#include "refs.h"
#include "object.h"
#include "tag.h"
+#include "path-list.h"
-static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*]";
+static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
static const char **pattern;
+static void show_one(const char *refname, const unsigned char *sha1)
+{
+ const char *hex = find_unique_abbrev(sha1, abbrev);
+ if (hash_only)
+ printf("%s\n", hex);
+ else
+ printf("%s %s\n", hex, refname);
+}
+
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
{
struct object *obj;
@@ -57,11 +67,7 @@ match:
if (quiet)
return 0;
- hex = find_unique_abbrev(sha1, abbrev);
- if (hash_only)
- printf("%s\n", hex);
- else
- printf("%s %s\n", hex, refname);
+ show_one(refname, sha1);
if (!deref_tags)
return 0;
@@ -86,6 +92,60 @@ match:
return 0;
}
+static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
+{
+ struct path_list *list = (struct path_list *)cbdata;
+ path_list_insert(refname, list);
+ return 0;
+}
+
+/*
+ * read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
+ * and
+ * (1) strip "^{}" at the end of line if any;
+ * (2) ignore if match is provided and does not head-match refname;
+ * (3) warn if refname is not a well-formed refname and skip;
+ * (4) ignore if refname is a ref that exists in the local repository;
+ * (5) otherwise output the line.
+ */
+static int exclude_existing(const char *match)
+{
+ static struct path_list existing_refs = { NULL, 0, 0, 0 };
+ char buf[1024];
+ int matchlen = match ? strlen(match) : 0;
+
+ for_each_ref(add_existing, &existing_refs);
+ while (fgets(buf, sizeof(buf), stdin)) {
+ char *ref;
+ int len = strlen(buf);
+
+ if (len > 0 && buf[len - 1] == '\n')
+ buf[--len] = '\0';
+ if (3 <= len && !strcmp(buf + len - 3, "^{}")) {
+ len -= 3;
+ buf[len] = '\0';
+ }
+ for (ref = buf + len; buf < ref; ref--)
+ if (isspace(ref[-1]))
+ break;
+ if (match) {
+ int reflen = buf + len - ref;
+ if (reflen < matchlen)
+ continue;
+ if (strncmp(ref, match, matchlen))
+ continue;
+ }
+ if (check_ref_format(ref)) {
+ fprintf(stderr, "warning: ref '%s' ignored\n", ref);
+ continue;
+ }
+ if (!path_list_has_path(&existing_refs, ref)) {
+ printf("%s\n", buf);
+ }
+ }
+ return 0;
+}
+
int cmd_show_ref(int argc, const char **argv, const char *prefix)
{
int i;
@@ -121,13 +181,13 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
if (!strncmp(arg, "--hash=", 7) ||
(!strncmp(arg, "--abbrev", 8) &&
(arg[8] == '=' || arg[8] == '\0'))) {
- if (arg[3] != 'h' && !arg[8])
+ if (arg[2] != 'h' && !arg[8])
/* --abbrev only */
abbrev = DEFAULT_ABBREV;
else {
/* --hash= or --abbrev= */
char *end;
- if (arg[3] == 'h') {
+ if (arg[2] == 'h') {
hash_only = 1;
arg += 7;
}
@@ -153,8 +213,31 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
heads_only = 1;
continue;
}
+ if (!strcmp(arg, "--exclude-existing"))
+ return exclude_existing(NULL);
+ if (!strncmp(arg, "--exclude-existing=", 19))
+ return exclude_existing(arg + 19);
usage(show_ref_usage);
}
+
+ if (verify) {
+ unsigned char sha1[20];
+
+ while (*pattern) {
+ if (!strncmp(*pattern, "refs/", 5) &&
+ resolve_ref(*pattern, sha1, 1, NULL)) {
+ if (!quiet)
+ show_one(*pattern, sha1);
+ }
+ else if (!quiet)
+ die("'%s' - not a valid ref", *pattern);
+ else
+ return 1;
+ pattern++;
+ }
+ return 0;
+ }
+
if (show_head)
head_ref(show_ref, NULL);
for_each_ref(show_ref, NULL);
diff --git a/cache.h b/cache.h
index 2d3df98dc..8ad5920d2 100644
--- a/cache.h
+++ b/cache.h
@@ -309,6 +309,7 @@ void datestamp(char *buf, int bufsize);
unsigned long approxidate(const char *);
extern int setup_ident(void);
+extern void ignore_missing_committer_name();
extern const char *git_author_info(int);
extern const char *git_committer_info(int);
@@ -404,6 +405,7 @@ extern int git_config_int(const char *, const char *);
extern int git_config_bool(const char *, const char *);
extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
+extern int git_config_rename_section(const char *, const char *);
extern int check_repository_format_version(const char *var, const char *value);
#define MAX_GITNAME (1000)
diff --git a/config.c b/config.c
index 1bdef44a3..663993fef 100644
--- a/config.c
+++ b/config.c
@@ -746,4 +746,68 @@ out_free:
return ret;
}
+int git_config_rename_section(const char *old_name, const char *new_name)
+{
+ int ret = 0;
+ const char *config_filename;
+ struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
+ int out_fd;
+ char buf[1024];
+
+ config_filename = getenv("GIT_CONFIG");
+ if (!config_filename) {
+ config_filename = getenv("GIT_CONFIG_LOCAL");
+ if (!config_filename)
+ config_filename = git_path("config");
+ }
+ config_filename = xstrdup(config_filename);
+ out_fd = hold_lock_file_for_update(lock, config_filename, 0);
+ if (out_fd < 0)
+ return error("Could not lock config file!");
+
+ if (!(config_file = fopen(config_filename, "rb")))
+ return error("Could not open config file!");
+
+ while (fgets(buf, sizeof(buf), config_file)) {
+ int i;
+ for (i = 0; buf[i] && isspace(buf[i]); i++)
+ ; /* do nothing */
+ if (buf[i] == '[') {
+ /* it's a section */
+ int j = 0, dot = 0;
+ for (i++; buf[i] && buf[i] != ']'; i++) {
+ if (!dot && isspace(buf[i])) {
+ dot = 1;
+ if (old_name[j++] != '.')
+ break;
+ for (i++; isspace(buf[i]); i++)
+ ; /* do nothing */
+ if (buf[i] != '"')
+ break;
+ continue;
+ }
+ if (buf[i] == '\\' && dot)
+ i++;
+ else if (buf[i] == '"' && dot) {
+ for (i++; isspace(buf[i]); i++)
+ ; /* do_nothing */
+ break;
+ }
+ if (buf[i] != old_name[j++])
+ break;
+ }
+ if (buf[i] == ']') {
+ /* old_name matches */
+ ret++;
+ store.baselen = strlen(new_name);
+ store_write_section(out_fd, new_name);
+ continue;
+ }
+ }
+ write(out_fd, buf, strlen(buf));
+ }
+ if (close(out_fd) || commit_lock_file(lock) < 0)
+ return error("Cannot commit config file!");
+ return ret;
+}
diff --git a/contrib/vim/syntax/gitcommit.vim b/contrib/vim/syntax/gitcommit.vim
index a9de09fa2..d911efbb4 100644
--- a/contrib/vim/syntax/gitcommit.vim
+++ b/contrib/vim/syntax/gitcommit.vim
@@ -1,7 +1,7 @@
syn region gitLine start=/^#/ end=/$/
-syn region gitCommit start=/^# Updated but not checked in:$/ end=/^#$/ contains=gitHead,gitCommitFile
+syn region gitCommit start=/^# Added but not yet committed:$/ end=/^#$/ contains=gitHead,gitCommitFile
syn region gitHead contained start=/^# (.*)/ end=/^#$/
-syn region gitChanged start=/^# Changed but not updated:/ end=/^#$/ contains=gitHead,gitChangedFile
+syn region gitChanged start=/^# Changed but not added:/ end=/^#$/ contains=gitHead,gitChangedFile
syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
syn match gitCommitFile contained /^#\t.*/hs=s+2
diff --git a/git-fetch.sh b/git-fetch.sh
index fb35815a5..ffbd44f0e 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -96,7 +96,7 @@ fi
# Global that is reused later
ls_remote_result=$(git ls-remote $upload_pack "$remote") ||
- die "Cannot find the reflist at $remote"
+ die "Cannot get the repository state from $remote"
append_fetch_head () {
head_="$1"
@@ -242,7 +242,7 @@ esac
reflist=$(get_remote_refs_for_fetch "$@")
if test "$tags"
then
- taglist=`IFS=" " &&
+ taglist=`IFS=' ' &&
echo "$ls_remote_result" |
while read sha1 name
do
@@ -438,17 +438,11 @@ case "$no_tags$tags" in
*:refs/*)
# effective only when we are following remote branch
# using local tracking branch.
- taglist=$(IFS=" " &&
+ taglist=$(IFS=' ' &&
echo "$ls_remote_result" |
- sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \
- -e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' |
+ git-show-ref --exclude-existing=refs/tags/ |
while read sha1 name
do
- git-show-ref --verify --quiet -- "$name" && continue
- git-check-ref-format "$name" || {
- echo >&2 "warning: tag ${name} ignored"
- continue
- }
git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
echo >&2 "Auto-following $name"
echo ".${name}:${name}"
diff --git a/git-ls-remote.sh b/git-ls-remote.sh
index 0f88953f2..03b624ef3 100755
--- a/git-ls-remote.sh
+++ b/git-ls-remote.sh
@@ -94,7 +94,7 @@ while read sha1 path
do
case "$sha1" in
failed)
- die "Failed to find remote refs"
+ exit 1 ;;
esac
case "$path" in
refs/heads/*)
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index f27c3c231..11c4aba24 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -111,16 +111,14 @@ expand_refs_wildcard () {
local_force=
test "z$lref" = "z$ref" || local_force='+'
echo "$ls_remote_result" |
+ sed -e '/\^{}$/d' |
(
IFS=' '
while read sha1 name
do
+ # ignore the ones that do not start with $from
mapped=${name#"$from"}
- if test "z$name" != "z${name%'^{}'}" ||
- test "z$name" = "z$mapped"
- then
- continue
- fi
+ test "z$name" = "z$mapped" && continue
echo "${local_force}${name}:${to}${mapped}"
done
)
diff --git a/git-rerere.perl b/git-rerere.perl
index fdd685489..4f692091e 100755
--- a/git-rerere.perl
+++ b/git-rerere.perl
@@ -154,7 +154,7 @@ sub find_conflict {
sub merge {
my ($name, $path) = @_;
record_preimage($path, "$rr_dir/$name/thisimage");
- unless (system('git merge-file', map { "$rr_dir/$name/${_}image" }
+ unless (system('git', 'merge-file', map { "$rr_dir/$name/${_}image" }
qw(this pre post))) {
my $in;
open $in, "<$rr_dir/$name/thisimage" or
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5ea3fda54..4059894e0 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -434,6 +434,7 @@ my %actions = (
"tags" => \&git_tags,
"tree" => \&git_tree,
"snapshot" => \&git_snapshot,
+ "object" => \&git_object,
# those below don't need $project
"opml" => \&git_opml,
"project_list" => \&git_project_list,
@@ -827,14 +828,12 @@ sub format_log_line_html {
my $line = shift;
$line = esc_html($line, -nbsp=>1);
- if ($line =~ m/([0-9a-fA-F]{40})/) {
+ if ($line =~ m/([0-9a-fA-F]{8,40})/) {
my $hash_text = $1;
- if (git_get_type($hash_text) eq "commit") {
- my $link =
- $cgi->a({-href => href(action=>"commit", hash=>$hash_text),
- -class => "text"}, $hash_text);
- $line =~ s/$hash_text/$link/;
- }
+ my $link =
+ $cgi->a({-href => href(action=>"object", hash=>$hash_text),
+ -class => "text"}, $hash_text);
+ $line =~ s/$hash_text/$link/;
}
return $line;
}
@@ -856,7 +855,8 @@ sub format_ref_marker {
$name = $ref;
}
- $markers .= " <span class=\"$type\">" . esc_html($name) . "</span>";
+ $markers .= " <span class=\"$type\" title=\"$ref\">" .
+ esc_html($name) . "</span>";
}
}
@@ -1989,12 +1989,73 @@ sub git_print_log ($;%) {
}
}
+# return link target (what link points to)
+sub git_get_link_target {
+ my $hash = shift;
+ my $link_target;
+
+ # read link
+ open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
+ or return;
+ {
+ local $/;
+ $link_target = <$fd>;
+ }
+ close $fd
+ or return;
+
+ return $link_target;
+}
+
+# given link target, and the directory (basedir) the link is in,
+# return target of link relative to top directory (top tree);
+# return undef if it is not possible (including absolute links).
+sub normalize_link_target {
+ my ($link_target, $basedir, $hash_base) = @_;
+
+ # we can normalize symlink target only if $hash_base is provided
+ return unless $hash_base;
+
+ # absolute symlinks (beginning with '/') cannot be normalized
+ return if (substr($link_target, 0, 1) eq '/');
+
+ # normalize link target to path from top (root) tree (dir)
+ my $path;
+ if ($basedir) {
+ $path = $basedir . '/' . $link_target;
+ } else {
+ # we are in top (root) tree (dir)
+ $path = $link_target;
+ }
+
+ # remove //, /./, and /../
+ my @path_parts;
+ foreach my $part (split('/', $path)) {
+ # discard '.' and ''
+ next if (!$part || $part eq '.');
+ # handle '..'
+ if ($part eq '..') {
+ if (@path_parts) {
+ pop @path_parts;
+ } else {
+ # link leads outside repository (outside top dir)
+ return;
+ }
+ } else {
+ push @path_parts, $part;
+ }
+ }
+ $path = join('/', @path_parts);
+
+ return $path;
+}
+
# print tree entry (row of git_tree), but without encompassing <tr> element
sub git_print_tree_entry {
my ($t, $basedir, $hash_base, $have_blame) = @_;
my %base_key = ();
- $base_key{hash_base} = $hash_base if defined $hash_base;
+ $base_key{'hash_base'} = $hash_base if defined $hash_base;
# The format of a table row is: mode list link. Where mode is
# the mode of the entry, list is the name of the entry, an href,
@@ -2005,16 +2066,31 @@ sub git_print_tree_entry {
print "<td class=\"list\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key),
- -class => "list"}, esc_path($t->{'name'})) . "</td>\n";
+ -class => "list"}, esc_path($t->{'name'}));
+ if (S_ISLNK(oct $t->{'mode'})) {
+ my $link_target = git_get_link_target($t->{'hash'});
+ if ($link_target) {
+ my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
+ if (defined $norm_target) {
+ print " -> " .
+ $cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
+ file_name=>$norm_target),
+ -title => $norm_target}, esc_path($link_target));
+ } else {
+ print " -> " . esc_path($link_target);
+ }
+ }
+ }
+ print "</td>\n";
print "<td class=\"link\">";
print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "blob");
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "blob");
if ($have_blame) {
print " | " .
$cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "blame");
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "blame");
}
if (defined $hash_base) {
print " | " .
@@ -2036,8 +2112,8 @@ sub git_print_tree_entry {
print "</td>\n";
print "<td class=\"link\">";
print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "tree");
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "tree");
if (defined $hash_base) {
print " | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
@@ -3414,8 +3490,7 @@ sub git_snapshot {
my $filename = basename($project) . "-$hash.tar.$suffix";
print $cgi->header(
- -type => 'application/x-tar',
- -content_encoding => $ctype,
+ -type => "application/$ctype",
-content_disposition => 'inline; filename="' . "$filename" . '"',
-status => '200 OK');
@@ -3497,15 +3572,46 @@ sub git_commit {
my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
- my $parent = $co{'parent'};
+ my $parent = $co{'parent'};
+ my $parents = $co{'parents'}; # listref
+
+ # we need to prepare $formats_nav before any parameter munging
+ my $formats_nav;
+ if (!defined $parent) {
+ # --root commitdiff
+ $formats_nav .= '(initial)';
+ } elsif (@$parents == 1) {
+ # single parent commit
+ $formats_nav .=
+ '(parent: ' .
+ $cgi->a({-href => href(action=>"commit",
+ hash=>$parent)},
+ esc_html(substr($parent, 0, 7))) .
+ ')';
+ } else {
+ # merge commit
+ $formats_nav .=
+ '(merge: ' .
+ join(' ', map {
+ $cgi->a({-href => href(action=>"commitdiff",
+ hash=>$_)},
+ esc_html(substr($_, 0, 7)));
+ } @$parents ) .
+ ')';
+ }
+
if (!defined $parent) {
$parent = "--root";
}
- open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
- @diff_opts, $parent, $hash, "--"
- or die_error(undef, "Open git-diff-tree failed");
- my @difftree = map { chomp; $_ } <$fd>;
- close $fd or die_error(undef, "Reading git-diff-tree failed");
+ my @difftree;
+ if (@$parents <= 1) {
+ # difftree output is not printed for merges
+ open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
+ @diff_opts, $parent, $hash, "--"
+ or die_error(undef, "Open git-diff-tree failed");
+ @difftree = map { chomp; $_ } <$fd>;
+ close $fd or die_error(undef, "Reading git-diff-tree failed");
+ }
# non-textual hash id's can be cached
my $expires;
@@ -3517,16 +3623,10 @@ sub git_commit {
my $have_snapshot = gitweb_have_snapshot();
- my @views_nav = ();
- if (defined $file_name && defined $co{'parent'}) {
- push @views_nav,
- $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
- "blame");
- }
git_header_html(undef, $expires);
git_print_page_nav('commit', '',
$hash, $co{'tree'}, $hash,
- join (' | ', @views_nav));
+ $formats_nav);
if (defined $co{'parent'}) {
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
@@ -3567,7 +3667,7 @@ sub git_commit {
}
print "</td>" .
"</tr>\n";
- my $parents = $co{'parents'};
+
foreach my $par (@$parents) {
print "<tr>" .
"<td>parent</td>" .
@@ -3589,11 +3689,61 @@ sub git_commit {
git_print_log($co{'comment'});
print "</div>\n";
- git_difftree_body(\@difftree, $hash, $parent);
+ if (@$parents <= 1) {
+ # do not output difftree/whatchanged for merges
+ git_difftree_body(\@difftree, $hash, $parent);
+ }
git_footer_html();
}
+sub git_object {
+ # object is defined by:
+ # - hash or hash_base alone
+ # - hash_base and file_name
+ my $type;
+
+ # - hash or hash_base alone
+ if ($hash || ($hash_base && !defined $file_name)) {
+ my $object_id = $hash || $hash_base;
+
+ my $git_command = git_cmd_str();
+ open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
+ or die_error('404 Not Found', "Object does not exist");
+ $type = <$fd>;
+ chomp $type;
+ close $fd
+ or die_error('404 Not Found', "Object does not exist");
+
+ # - hash_base and file_name
+ } elsif ($hash_base && defined $file_name) {
+ $file_name =~ s,/+$,,;
+
+ system(git_cmd(), "cat-file", '-e', $hash_base) == 0
+ or die_error('404 Not Found', "Base object does not exist");
+
+ # here errors should not hapen
+ open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
+ or die_error(undef, "Open git-ls-tree failed");
+ my $line = <$fd>;
+ close $fd;
+
+ #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
+ unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
+ die_error('404 Not Found', "File or directory for given base does not exist");
+ }
+ $type = $2;
+ $hash = $3;
+ } else {
+ die_error('404 Not Found', "Not enough information to find object");
+ }
+
+ print $cgi->redirect(-uri => href(action=>$type, -full=>1,
+ hash=>$hash, hash_base=>$hash_base,
+ file_name=>$file_name),
+ -status => '302 Found');
+}
+
sub git_blobdiff {
my $format = shift || 'html';
diff --git a/ident.c b/ident.c
index e415fd358..d7faba6a7 100644
--- a/ident.c
+++ b/ident.c
@@ -221,3 +221,18 @@ const char *git_committer_info(int error_on_no_name)
getenv("GIT_COMMITTER_DATE"),
error_on_no_name);
}
+
+void ignore_missing_committer_name()
+{
+ /* If we did not get a name from the user's gecos entry then
+ * git_default_name is empty; so instead load the username
+ * into it as a 'good enough for now' approximation of who
+ * this user is.
+ */
+ if (!*git_default_name) {
+ struct passwd *pw = getpwuid(getuid());
+ if (!pw)
+ die("You don't exist. Go away!");
+ strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name));
+ }
+}
diff --git a/patch-delta.c b/patch-delta.c
index e3a1d425e..ed9db81fa 100644
--- a/patch-delta.c
+++ b/patch-delta.c
@@ -9,8 +9,7 @@
* published by the Free Software Foundation.
*/
-#include <stdlib.h>
-#include <string.h>
+#include "git-compat-util.h"
#include "delta.h"
void *patch_delta(const void *src_buf, unsigned long src_size,
@@ -34,9 +33,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
/* now the result size */
size = get_delta_hdr_size(&data, top);
- dst_buf = malloc(size + 1);
- if (!dst_buf)
- return NULL;
+ dst_buf = xmalloc(size + 1);
dst_buf[size] = 0;
out = dst_buf;
@@ -55,13 +52,13 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
if (cp_off + cp_size < cp_size ||
cp_off + cp_size > src_size ||
cp_size > size)
- goto bad;
+ break;
memcpy(out, (char *) src_buf + cp_off, cp_size);
out += cp_size;
size -= cp_size;
} else if (cmd) {
if (cmd > size)
- goto bad;
+ break;
memcpy(out, data, cmd);
out += cmd;
data += cmd;
@@ -72,12 +69,14 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
* extensions. In the mean time we must fail when
* encountering them (might be data corruption).
*/
+ error("unexpected delta opcode 0");
goto bad;
}
}
/* sanity check */
if (data != top || size != 0) {
+ error("delta replay has gone wild");
bad:
free(dst_buf);
return NULL;
diff --git a/pkt-line.c b/pkt-line.c
index c1e81f976..b4cb7e275 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -72,7 +72,7 @@ static void safe_read(int fd, void *buffer, unsigned size)
if (ret < 0)
die("read error (%s)", strerror(errno));
if (!ret)
- die("unexpected EOF");
+ die("The remote end hung up unexpectedly");
n += ret;
}
}
diff --git a/read-cache.c b/read-cache.c
index eae4745d2..b8d83ccd9 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -358,7 +358,7 @@ int add_file_to_index(const char *path, int verbose)
if (index_path(ce->sha1, path, &st, 1))
die("unable to index file %s", path);
- if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD))
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
die("unable to add %s to index",path);
if (verbose)
printf("add '%s'\n", path);
@@ -517,7 +517,7 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
if (pos >= 0) {
retval = -1;
- if (ok_to_replace)
+ if (!ok_to_replace)
break;
remove_cache_entry_at(pos);
continue;
@@ -609,7 +609,7 @@ int add_cache_entry(struct cache_entry *ce, int option)
if (!skip_df_check &&
check_file_directory_conflict(ce, pos, ok_to_replace)) {
if (!ok_to_replace)
- return -1;
+ return error("'%s' appears as both a file and as a directory", ce->name);
pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
pos = -pos-1;
}
diff --git a/receive-pack.c b/receive-pack.c
index e76d9aea3..5e5510bc3 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -420,6 +420,8 @@ int main(int argc, char **argv)
die("'%s': unable to chdir or not a git archive", dir);
setup_ident();
+ /* don't die if gecos is empty */
+ ignore_missing_committer_name();
git_config(receive_pack_config);
write_head_info();
diff --git a/refs.c b/refs.c
index a02957c39..d911b9e86 100644
--- a/refs.c
+++ b/refs.c
@@ -867,6 +867,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
goto rollback;
}
+ if (!strncmp(oldref, "refs/heads/", 11) &&
+ !strncmp(newref, "refs/heads/", 11)) {
+ char oldsection[1024], newsection[1024];
+
+ snprintf(oldsection, 1024, "branch.%s", oldref + 11);
+ snprintf(newsection, 1024, "branch.%s", newref + 11);
+ if (git_config_rename_section(oldsection, newsection) < 0)
+ return 1;
+ }
+
return 0;
rollback:
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 3260d1d7a..0cd1c4186 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -272,4 +272,13 @@ test_expect_success \
wc -l) &&
test $numparent = 1'
+test_expect_success 'update-index D/F conflict' '
+ mv path0 tmp &&
+ mv path2 path0 &&
+ mv tmp path2 &&
+ git update-index --add --replace path2 path0/file2 &&
+ numpath0=$(git ls-files path0 | wc -l) &&
+ test $numpath0 = 1
+'
+
test_done
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 16cd64261..e48a4ecdc 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -343,5 +343,53 @@ EOF
test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+cat > .git/config << EOF
+# Hallo
+ #Bello
+[branch "eins"]
+ x = 1
+[branch.eins]
+ y = 1
+ [branch "1 234 blabl/a"]
+weird
+EOF
+
+test_expect_success "rename section" \
+ "git-repo-config --rename-section branch.eins branch.zwei"
+
+cat > expect << EOF
+# Hallo
+ #Bello
+[branch "zwei"]
+ x = 1
+[branch "zwei"]
+ y = 1
+ [branch "1 234 blabl/a"]
+weird
+EOF
+
+test_expect_success "rename succeeded" "diff -u expect .git/config"
+
+test_expect_failure "rename non-existing section" \
+ 'git-repo-config --rename-section branch."world domination" branch.drei'
+
+test_expect_success "rename succeeded" "diff -u expect .git/config"
+
+test_expect_success "rename another section" \
+ 'git-repo-config --rename-section branch."1 234 blabl/a" branch.drei'
+
+cat > expect << EOF
+# Hallo
+ #Bello
+[branch "zwei"]
+ x = 1
+[branch "zwei"]
+ y = 1
+[branch "drei"]
+weird
+EOF
+
+test_expect_success "rename succeeded" "diff -u expect .git/config"
+
test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 5782c30b0..a6ea0f6a1 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -94,6 +94,8 @@ test_expect_failure \
git-branch r &&
git-branch -m q r/q'
+git-repo-config branch.s/s.dummy Hello
+
test_expect_success \
'git branch -m s/s s should work when s/t is deleted' \
'git-branch -l s/s &&
@@ -104,6 +106,10 @@ test_expect_success \
git-branch -m s/s s &&
test -f .git/logs/refs/heads/s'
+test_expect_success 'config information was renamed, too' \
+ "test $(git-repo-config branch.s.dummy) = Hello &&
+ ! git-repo-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 &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index ac7be769b..f0f9cd6be 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -208,8 +208,9 @@ test_done () {
# t/ subdirectory and are run in trash subdirectory.
PATH=$(pwd)/..:$PATH
GIT_EXEC_PATH=$(pwd)/..
+GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
HOME=$(pwd)/trash
-export PATH GIT_EXEC_PATH HOME
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR HOME
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
export GITPERLLIB