summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/CodingGuidelines12
-rw-r--r--Documentation/RelNotes/2.27.0.txt27
-rw-r--r--Documentation/git-bugreport.txt1
-rw-r--r--Documentation/git-multi-pack-index.txt3
-rw-r--r--Documentation/technical/commit-graph-format.txt8
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile8
-rw-r--r--bloom.c56
-rw-r--r--bloom.h4
-rw-r--r--bugreport.c52
-rw-r--r--compat/gmtime.c29
-rw-r--r--config.mak.uname1
-rw-r--r--contrib/completion/git-completion.bash1
-rw-r--r--fsck.c72
-rwxr-xr-xgit-bisect.sh2
-rw-r--r--git-compat-util.h7
-rwxr-xr-xgit-p4.py43
-rw-r--r--midx.c42
-rw-r--r--progress.c17
-rw-r--r--sequencer.c7
-rw-r--r--t/helper/test-bloom.c2
-rwxr-xr-xt/t0091-bugreport.sh15
-rwxr-xr-xt/t0095-bloom.sh6
-rwxr-xr-xt/t0500-progress-display.sh26
-rwxr-xr-xt/t1450-fsck.sh16
-rwxr-xr-xt/t1509-root-work-tree.sh4
-rwxr-xr-xt/t3415-rebase-autosquash.sh16
-rwxr-xr-xt/t5319-multi-pack-index.sh27
-rwxr-xr-xt/t5500-fetch-pack.sh12
-rwxr-xr-xt/t6030-bisect-porcelain.sh7
-rwxr-xr-xt/t9834-git-p4-file-dir-bug.sh70
31 files changed, 502 insertions, 93 deletions
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index a89e8dcfbc..227f46ae40 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -232,6 +232,18 @@ For C programs:
while( condition )
func (bar+1);
+ - Do not explicitly compare an integral value with constant 0 or '\0',
+ or a pointer value with constant NULL. For instance, to validate that
+ counted array <ptr, cnt> is initialized but has no elements, write:
+
+ if (!ptr || cnt)
+ BUG("empty array expected");
+
+ and not:
+
+ if (ptr == NULL || cnt != 0);
+ BUG("empty array expected");
+
- We avoid using braces unnecessarily. I.e.
if (bla) {
diff --git a/Documentation/RelNotes/2.27.0.txt b/Documentation/RelNotes/2.27.0.txt
index b398961c8a..e3121d0164 100644
--- a/Documentation/RelNotes/2.27.0.txt
+++ b/Documentation/RelNotes/2.27.0.txt
@@ -108,6 +108,13 @@ UI, Workflows & Features
* "git restore --staged --worktree" now defaults to take the contents
out of "HEAD", instead of erring out.
+ * "git p4" learned to recover from a (broken) state where a directory
+ and a file are recorded at the same path in the Perforce repository
+ the same way as their clients do.
+
+ * "git multi-pack-index repack" has been taught to honor some
+ repack.* configuration variables.
+
Performance, Internal Implementation, Development Support etc.
@@ -167,6 +174,10 @@ Performance, Internal Implementation, Development Support etc.
* Instead of always building all branches at GitHub via Actions,
users can specify which branches to build.
+ * Codepaths that show progress meter have been taught to also use the
+ start_progress() and the stop_progress() calls as a "region" to be
+ traced.
+
Fixes since v2.26
-----------------
@@ -444,6 +455,21 @@ Fixes since v2.26
e.g. auto-follow tags.
(merge 08450ef791 cc/upload-pack-v2-fetch-fix later to maint).
+ * "git bisect replay" had trouble with input files when they used
+ CRLF line ending, which has been corrected.
+ (merge 6c722cbe5a cw/bisect-replay-with-dos later to maint).
+
+ * "rebase -i" segfaulted when rearranging a sequence that has a
+ fix-up that applies another fix-up (which may or may not be a
+ fix-up of yet another step).
+ (merge 02471e7e20 js/rebase-autosquash-double-fixup-fix later to maint).
+
+ * "git fsck" ensures that the paths recorded in tree objects are
+ sorted and without duplicates, but it failed to notice a case where
+ a blob is followed by entries that sort before a tree with the same
+ name. This has been corrected.
+ (merge 9068cfb20f rs/fsck-duplicate-names-in-trees later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 564956f358 jc/maintain-doc later to maint).
(merge 7422b2a0a1 sg/commit-slab-clarify-peek later to maint).
@@ -472,3 +498,4 @@ Fixes since v2.26
(merge bdccbf7047 mt/doc-worktree-ref later to maint).
(merge ce9baf234f dl/push-recurse-submodules-fix later to maint).
(merge 4153274052 bc/doc-credential-helper-value later to maint).
+ (merge 5c7bb0146e jc/codingstyle-compare-with-null later to maint).
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 643d1b2884..7fe9aef34e 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -28,6 +28,7 @@ The following information is captured automatically:
- 'git version --build-options'
- uname sysname, release, version, and machine strings
- Compiler-specific info string
+ - A list of enabled hooks
This tool is invoked via the typical Git setup process, which means that in some
cases, it might not be able to launch - for example, if a relevant config file
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 642d9ac5b7..0c6619493c 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -56,6 +56,9 @@ repack::
file is created, rewrite the multi-pack-index to reference the
new pack-file. A later run of 'git multi-pack-index expire' will
delete the pack-files that were part of this batch.
++
+If `repack.packKeptObjects` is `false`, then any pack-files with an
+associated `.keep` file will not be selected for the batch to repack.
EXAMPLES
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index de56f9f1ef..1beef17182 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -97,10 +97,10 @@ CHUNK DATA:
bit on. The other bits correspond to the position of the last parent.
Bloom Filter Index (ID: {'B', 'I', 'D', 'X'}) (N * 4 bytes) [Optional]
- * The ith entry, BIDX[i], stores the number of 8-byte word blocks in all
- Bloom filters from commit 0 to commit i (inclusive) in lexicographic
- order. The Bloom filter for the i-th commit spans from BIDX[i-1] to
- BIDX[i] (plus header length), where BIDX[-1] is 0.
+ * The ith entry, BIDX[i], stores the number of bytes in all Bloom filters
+ from commit 0 to commit i (inclusive) in lexicographic order. The Bloom
+ filter for the i-th commit spans from BIDX[i-1] to BIDX[i] (plus header
+ length), where BIDX[-1] is 0.
* The BIDX chunk is ignored if the BDAT chunk is not present.
Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 21f929e7ee..03d2243c0d 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.26.GIT
+DEF_VER=v2.27.0-rc0
LF='
'
diff --git a/Makefile b/Makefile
index 3d3a39fc19..90aa329eb7 100644
--- a/Makefile
+++ b/Makefile
@@ -399,9 +399,6 @@ all::
# with a different indexfile format version. If it isn't set the index
# file format used is index-v[23].
#
-# Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not
-# return NULL when it receives a bogus time_t.
-#
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime.
#
# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC.
@@ -1809,11 +1806,6 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS
MSGFMT += --check --statistics
endif
-ifdef GMTIME_UNRELIABLE_ERRORS
- COMPAT_OBJS += compat/gmtime.o
- BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS
-endif
-
ifdef HAVE_CLOCK_GETTIME
BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
endif
diff --git a/bloom.c b/bloom.c
index ee025e0c61..9b86aa3f59 100644
--- a/bloom.c
+++ b/bloom.c
@@ -29,8 +29,8 @@ static inline unsigned char get_bitmask(uint32_t pos)
}
static int load_bloom_filter_from_graph(struct commit_graph *g,
- struct bloom_filter *filter,
- struct commit *c)
+ struct bloom_filter *filter,
+ struct commit *c)
{
uint32_t lex_pos, start_index, end_index;
@@ -123,9 +123,9 @@ uint32_t murmur3_seeded(uint32_t seed, const char *data, size_t len)
}
void fill_bloom_key(const char *data,
- size_t len,
- struct bloom_key *key,
- const struct bloom_filter_settings *settings)
+ size_t len,
+ struct bloom_key *key,
+ const struct bloom_filter_settings *settings)
{
int i;
const uint32_t seed0 = 0x293ae76f;
@@ -139,8 +139,8 @@ void fill_bloom_key(const char *data,
}
void add_key_to_filter(const struct bloom_key *key,
- struct bloom_filter *filter,
- const struct bloom_filter_settings *settings)
+ struct bloom_filter *filter,
+ const struct bloom_filter_settings *settings)
{
int i;
uint64_t mod = filter->len * BITS_PER_WORD;
@@ -158,9 +158,22 @@ void init_bloom_filters(void)
init_bloom_filter_slab(&bloom_filters);
}
+static int pathmap_cmp(const void *hashmap_cmp_fn_data,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
+{
+ const struct pathmap_hash_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct pathmap_hash_entry, entry);
+ e2 = container_of(entry_or_key, const struct pathmap_hash_entry, entry);
+
+ return strcmp(e1->path, e2->path);
+}
+
struct bloom_filter *get_bloom_filter(struct repository *r,
struct commit *c,
- int compute_if_not_present)
+ int compute_if_not_present)
{
struct bloom_filter *filter;
struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
@@ -193,35 +206,42 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
diffopt.max_changes = max_changes;
diff_setup_done(&diffopt);
+ /* ensure commit is parsed so we have parent information */
+ repo_parse_commit(r, c);
+
if (c->parents)
diff_tree_oid(&c->parents->item->object.oid, &c->object.oid, "", &diffopt);
else
diff_tree_oid(NULL, &c->object.oid, "", &diffopt);
diffcore_std(&diffopt);
- if (diff_queued_diff.nr <= max_changes) {
+ if (diffopt.num_changes <= max_changes) {
struct hashmap pathmap;
struct pathmap_hash_entry *e;
struct hashmap_iter iter;
- hashmap_init(&pathmap, NULL, NULL, 0);
+ hashmap_init(&pathmap, pathmap_cmp, NULL, 0);
for (i = 0; i < diff_queued_diff.nr; i++) {
const char *path = diff_queued_diff.queue[i]->two->path;
/*
- * Add each leading directory of the changed file, i.e. for
- * 'dir/subdir/file' add 'dir' and 'dir/subdir' as well, so
- * the Bloom filter could be used to speed up commands like
- * 'git log dir/subdir', too.
- *
- * Note that directories are added without the trailing '/'.
- */
+ * Add each leading directory of the changed file, i.e. for
+ * 'dir/subdir/file' add 'dir' and 'dir/subdir' as well, so
+ * the Bloom filter could be used to speed up commands like
+ * 'git log dir/subdir', too.
+ *
+ * Note that directories are added without the trailing '/'.
+ */
do {
char *last_slash = strrchr(path, '/');
FLEX_ALLOC_STR(e, path, path);
hashmap_entry_init(&e->entry, strhash(path));
- hashmap_add(&pathmap, &e->entry);
+
+ if (!hashmap_get(&pathmap, &e->entry, NULL))
+ hashmap_add(&pathmap, &e->entry);
+ else
+ free(e);
if (!last_slash)
last_slash = (char*)path;
diff --git a/bloom.h b/bloom.h
index e0e59e0754..b2a8379a71 100644
--- a/bloom.h
+++ b/bloom.h
@@ -74,8 +74,8 @@ void fill_bloom_key(const char *data,
const struct bloom_filter_settings *settings);
void add_key_to_filter(const struct bloom_key *key,
- struct bloom_filter *filter,
- const struct bloom_filter_settings *settings);
+ struct bloom_filter *filter,
+ const struct bloom_filter_settings *settings);
void init_bloom_filters(void);
diff --git a/bugreport.c b/bugreport.c
index acacca8fef..aa8a489c35 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -3,6 +3,8 @@
#include "strbuf.h"
#include "help.h"
#include "compat/compiler.h"
+#include "run-command.h"
+
static void get_system_info(struct strbuf *sys_info)
{
@@ -31,6 +33,53 @@ static void get_system_info(struct strbuf *sys_info)
get_libc_info(sys_info);
}
+static void get_populated_hooks(struct strbuf *hook_info, int nongit)
+{
+ /*
+ * NEEDSWORK: Doesn't look like there is a list of all possible hooks;
+ * so below is a transcription of `git help hooks`. Later, this should
+ * be replaced with some programmatically generated list (generated from
+ * doc or else taken from some library which tells us about all the
+ * hooks)
+ */
+ static const char *hook[] = {
+ "applypatch-msg",
+ "pre-applypatch",
+ "post-applypatch",
+ "pre-commit",
+ "pre-merge-commit",
+ "prepare-commit-msg",
+ "commit-msg",
+ "post-commit",
+ "pre-rebase",
+ "post-checkout",
+ "post-merge",
+ "pre-push",
+ "pre-receive",
+ "update",
+ "post-receive",
+ "post-update",
+ "push-to-checkout",
+ "pre-auto-gc",
+ "post-rewrite",
+ "sendemail-validate",
+ "fsmonitor-watchman",
+ "p4-pre-submit",
+ "post-index-change",
+ };
+ int i;
+
+ if (nongit) {
+ strbuf_addstr(hook_info,
+ _("not run from a git repository - no hooks to show\n"));
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hook); i++)
+ if (find_hook(hook[i]))
+ strbuf_addf(hook_info, "%s\n", hook[i]);
+}
+
static const char * const bugreport_usage[] = {
N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
NULL
@@ -114,6 +163,9 @@ int cmd_main(int argc, const char **argv)
get_header(&buffer, _("System Info"));
get_system_info(&buffer);
+ get_header(&buffer, _("Enabled Hooks"));
+ get_populated_hooks(&buffer, nongit_ok);
+
/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
diff --git a/compat/gmtime.c b/compat/gmtime.c
deleted file mode 100644
index e8362dd2b9..0000000000
--- a/compat/gmtime.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "../git-compat-util.h"
-#undef gmtime
-#undef gmtime_r
-
-struct tm *git_gmtime(const time_t *timep)
-{
- static struct tm result;
- return git_gmtime_r(timep, &result);
-}
-
-struct tm *git_gmtime_r(const time_t *timep, struct tm *result)
-{
- struct tm *ret;
-
- memset(result, 0, sizeof(*result));
- ret = gmtime_r(timep, result);
-
- /*
- * Rather than NULL, FreeBSD gmtime simply leaves the "struct tm"
- * untouched when it encounters overflow. Since "mday" cannot otherwise
- * be zero, we can test this very quickly.
- */
- if (ret && !ret->tm_mday) {
- ret = NULL;
- errno = EOVERFLOW;
- }
-
- return ret;
-}
diff --git a/config.mak.uname b/config.mak.uname
index 5ad43c80b1..c7eba69e54 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -246,7 +246,6 @@ ifeq ($(uname_S),FreeBSD)
PYTHON_PATH = /usr/local/bin/python
PERL_PATH = /usr/local/bin/perl
HAVE_PATHS_H = YesPlease
- GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes
HAVE_BSD_SYSCTL = YesPlease
HAVE_BSD_KERN_PROC_SYSCTL = YesPlease
PAGER_ENV = LESS=FRX LV=-c MORE=FRX
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index b1d6e5ebed..70ad04e1b2 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1860,6 +1860,7 @@ _git_log ()
$merge
$__git_diff_common_options
--pickaxe-all --pickaxe-regex
+ --patch --no-patch
"
return
;;
diff --git a/fsck.c b/fsck.c
index 087a7f1ffc..8bb3ecf282 100644
--- a/fsck.c
+++ b/fsck.c
@@ -523,6 +523,28 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
}
}
+struct name_stack {
+ const char **names;
+ size_t nr, alloc;
+};
+
+static void name_stack_push(struct name_stack *stack, const char *name)
+{
+ ALLOC_GROW(stack->names, stack->nr + 1, stack->alloc);
+ stack->names[stack->nr++] = name;
+}
+
+static const char *name_stack_pop(struct name_stack *stack)
+{
+ return stack->nr ? stack->names[--stack->nr] : NULL;
+}
+
+static void name_stack_clear(struct name_stack *stack)
+{
+ FREE_AND_NULL(stack->names);
+ stack->nr = stack->alloc = 0;
+}
+
/*
* The entries in a tree are ordered in the _path_ order,
* which means that a directory entry is ordered by adding
@@ -534,7 +556,14 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
#define TREE_UNORDERED (-1)
#define TREE_HAS_DUPS (-2)
-static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
+static int is_less_than_slash(unsigned char c)
+{
+ return '\0' < c && c < '/';
+}
+
+static int verify_ordered(unsigned mode1, const char *name1,
+ unsigned mode2, const char *name2,
+ struct name_stack *candidates)
{
int len1 = strlen(name1);
int len2 = strlen(name2);
@@ -566,6 +595,41 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
c1 = '/';
if (!c2 && S_ISDIR(mode2))
c2 = '/';
+
+ /*
+ * There can be non-consecutive duplicates due to the implicitly
+ * add slash, e.g.:
+ *
+ * foo
+ * foo.bar
+ * foo.bar.baz
+ * foo.bar/
+ * foo/
+ *
+ * Record non-directory candidates (like "foo" and "foo.bar" in
+ * the example) on a stack and check directory candidates (like
+ * foo/" and "foo.bar/") against that stack.
+ */
+ if (!c1 && is_less_than_slash(c2)) {
+ name_stack_push(candidates, name1);
+ } else if (c2 == '/' && is_less_than_slash(c1)) {
+ for (;;) {
+ const char *p;
+ const char *f_name = name_stack_pop(candidates);
+
+ if (!f_name)
+ break;
+ if (!skip_prefix(name2, f_name, &p))
+ break;
+ if (!*p)
+ return TREE_HAS_DUPS;
+ if (is_less_than_slash(*p)) {
+ name_stack_push(candidates, f_name);
+ break;
+ }
+ }
+ }
+
return c1 < c2 ? 0 : TREE_UNORDERED;
}
@@ -587,6 +651,7 @@ static int fsck_tree(const struct object_id *oid,
struct tree_desc desc;
unsigned o_mode;
const char *o_name;
+ struct name_stack df_dup_candidates = { NULL };
if (init_tree_desc_gently(&desc, buffer, size)) {
retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
@@ -666,7 +731,8 @@ static int fsck_tree(const struct object_id *oid,
}
if (o_name) {
- switch (verify_ordered(o_mode, o_name, mode, name)) {
+ switch (verify_ordered(o_mode, o_name, mode, name,
+ &df_dup_candidates)) {
case TREE_UNORDERED:
not_properly_sorted = 1;
break;
@@ -682,6 +748,8 @@ static int fsck_tree(const struct object_id *oid,
o_name = name;
}
+ name_stack_clear(&df_dup_candidates);
+
if (has_null_sha1)
retval += report(options, oid, OBJ_TREE, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
if (has_full_path)
diff --git a/git-bisect.sh b/git-bisect.sh
index efee12b8b1..71b367a944 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -209,6 +209,7 @@ bisect_replay () {
test "$#" -eq 1 || die "$(gettext "No logfile given")"
test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
git bisect--helper --bisect-reset || exit
+ oIFS="$IFS" IFS="$IFS$(printf '\015')"
while read git bisect command rev
do
test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue
@@ -232,6 +233,7 @@ bisect_replay () {
die "$(gettext "?? what are you talking about?")" ;;
esac
done <"$file"
+ IFS="$oIFS"
bisect_auto_next
}
diff --git a/git-compat-util.h b/git-compat-util.h
index 8ba576e81e..a73632e8e4 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1216,13 +1216,6 @@ int access_or_die(const char *path, int mode, unsigned flag);
/* Warn on an inaccessible file if errno indicates this is an error */
int warn_on_fopen_errors(const char *path);
-#ifdef GMTIME_UNRELIABLE_ERRORS
-struct tm *git_gmtime(const time_t *);
-struct tm *git_gmtime_r(const time_t *, struct tm *);
-#define gmtime git_gmtime
-#define gmtime_r git_gmtime_r
-#endif
-
#if !defined(USE_PARENS_AROUND_GETTEXT_N) && defined(__GNUC__)
#define USE_PARENS_AROUND_GETTEXT_N 1
#endif
diff --git a/git-p4.py b/git-p4.py
index b8b2a1679e..d551efb0dd 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -3214,6 +3214,42 @@ class P4Sync(Command, P4UserMap):
print('Ignoring file outside of prefix: {0}'.format(path))
return hasPrefix
+ def findShadowedFiles(self, files, change):
+ # Perforce allows you commit files and directories with the same name,
+ # so you could have files //depot/foo and //depot/foo/bar both checked
+ # in. A p4 sync of a repository in this state fails. Deleting one of
+ # the files recovers the repository.
+ #
+ # Git will not allow the broken state to exist and only the most recent
+ # of the conflicting names is left in the repository. When one of the
+ # conflicting files is deleted we need to re-add the other one to make
+ # sure the git repository recovers in the same way as perforce.
+ deleted = [f for f in files if f['action'] in self.delete_actions]
+ to_check = set()
+ for f in deleted:
+ path = decode_path(f['path'])
+ to_check.add(path + '/...')
+ while True:
+ path = path.rsplit("/", 1)[0]
+ if path == "/" or path in to_check:
+ break
+ to_check.add(path)
+ to_check = ['%s@%s' % (wildcard_encode(p), change) for p in to_check
+ if self.hasBranchPrefix(p)]
+ if to_check:
+ stat_result = p4CmdList(["-x", "-", "fstat", "-T",
+ "depotFile,headAction,headRev,headType"], stdin=to_check)
+ for record in stat_result:
+ if record['code'] != 'stat':
+ continue
+ if record['headAction'] in self.delete_actions:
+ continue
+ files.append({
+ 'action': 'add',
+ 'path': record['depotFile'],
+ 'rev': record['headRev'],
+ 'type': record['headType']})
+
def commit(self, details, files, branch, parent = "", allow_empty=False):
epoch = details["time"]
author = details["user"]
@@ -3222,11 +3258,14 @@ class P4Sync(Command, P4UserMap):
if self.verbose:
print('commit into {0}'.format(branch))
+ files = [f for f in files
+ if self.hasBranchPrefix(decode_path(f['path']))]
+ self.findShadowedFiles(files, details['change'])
+
if self.clientSpecDirs:
self.clientSpecDirs.update_client_spec_path_cache(files)
- files = [f for (f, path) in ((f, decode_path(f['path'])) for f in files)
- if self.inClientSpec(path) and self.hasBranchPrefix(path)]
+ files = [f for f in files if self.inClientSpec(decode_path(f['path']))]
if gitConfigBool('git-p4.keepEmptyCommits'):
allow_empty = True
diff --git a/midx.c b/midx.c
index 9a61d3b37d..6d1584ca51 100644
--- a/midx.c
+++ b/midx.c
@@ -1293,15 +1293,26 @@ static int compare_by_mtime(const void *a_, const void *b_)
return 0;
}
-static int fill_included_packs_all(struct multi_pack_index *m,
+static int fill_included_packs_all(struct repository *r,
+ struct multi_pack_index *m,
unsigned char *include_pack)
{
- uint32_t i;
+ uint32_t i, count = 0;
+ int pack_kept_objects = 0;
+
+ repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
+
+ for (i = 0; i < m->num_packs; i++) {
+ if (prepare_midx_pack(r, m, i))
+ continue;
+ if (!pack_kept_objects && m->packs[i]->pack_keep)
+ continue;
- for (i = 0; i < m->num_packs; i++)
include_pack[i] = 1;
+ count++;
+ }
- return m->num_packs < 2;
+ return count < 2;
}
static int fill_included_packs_batch(struct repository *r,
@@ -1312,6 +1323,9 @@ static int fill_included_packs_batch(struct repository *r,
uint32_t i, packs_to_repack;
size_t total_size;
struct repack_info *pack_info = xcalloc(m->num_packs, sizeof(struct repack_info));
+ int pack_kept_objects = 0;
+
+ repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
for (i = 0; i < m->num_packs; i++) {
pack_info[i].pack_int_id = i;
@@ -1338,6 +1352,8 @@ static int fill_included_packs_batch(struct repository *r,
if (!p)
continue;
+ if (!pack_kept_objects && p->pack_keep)
+ continue;
if (open_pack_index(p) || !p->num_objects)
continue;
@@ -1370,6 +1386,14 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
struct strbuf base_name = STRBUF_INIT;
struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+ /*
+ * When updating the default for these configuration
+ * variables in builtin/repack.c, these must be adjusted
+ * to match.
+ */
+ int delta_base_offset = 1;
+ int use_delta_islands = 0;
+
if (!m)
return 0;
@@ -1378,15 +1402,23 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
if (batch_size) {
if (fill_included_packs_batch(r, m, include_pack, batch_size))
goto cleanup;
- } else if (fill_included_packs_all(m, include_pack))
+ } else if (fill_included_packs_all(r, m, include_pack))
goto cleanup;
+ repo_config_get_bool(r, "repack.usedeltabaseoffset", &delta_base_offset);
+ repo_config_get_bool(r, "repack.usedeltaislands", &use_delta_islands);
+
argv_array_push(&cmd.args, "pack-objects");
strbuf_addstr(&base_name, object_dir);
strbuf_addstr(&base_name, "/pack/pack");
argv_array_push(&cmd.args, base_name.buf);
+ if (delta_base_offset)
+ argv_array_push(&cmd.args, "--delta-base-offset");
+ if (use_delta_islands)
+ argv_array_push(&cmd.args, "--delta-islands");
+
if (flags & MIDX_PROGRESS)
argv_array_push(&cmd.args, "--progress");
else
diff --git a/progress.c b/progress.c
index 75633e9c5e..6d2dcff0b6 100644
--- a/progress.c
+++ b/progress.c
@@ -265,6 +265,7 @@ static struct progress *start_progress_delay(const char *title, uint64_t total,
progress->title_len = utf8_strwidth(title);
progress->split = 0;
set_progress_signal();
+ trace2_region_enter("progress", title, the_repository);
return progress;
}
@@ -320,6 +321,22 @@ void stop_progress(struct progress **p_progress)
{
finish_if_sparse(*p_progress);
+ if (p_progress && *p_progress) {
+ trace2_data_intmax("progress", the_repository, "total_objects",
+ (*p_progress)->total);
+
+ if ((*p_progress)->throughput)
+ trace2_data_intmax("progress", the_repository,
+ "total_bytes",
+ (*p_progress)->throughput->curr_total);
+ }
+
+ trace2_region_leave("progress",
+ p_progress && *p_progress
+ ? (*p_progress)->title
+ : NULL,
+ the_repository);
+
stop_progress_msg(p_progress, _("done"));
}
diff --git a/sequencer.c b/sequencer.c
index 9d1b3e7d4f..fd7701c88a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -5385,10 +5385,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
todo_list->items[i].command =
starts_with(subject, "fixup!") ?
TODO_FIXUP : TODO_SQUASH;
- if (next[i2] < 0)
+ if (tail[i2] < 0) {
+ next[i] = next[i2];
next[i2] = i;
- else
+ } else {
+ next[i] = next[tail[i2]];
next[tail[i2]] = i;
+ }
tail[i2] = i;
} else if (!hashmap_get_from_hash(&subject2item,
strhash(subject), subject)) {
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index 456f5ea7f9..f0aa80b98e 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -44,7 +44,7 @@ static void get_bloom_filter_for_commit(const struct object_id *commit_oid)
}
static const char *bloom_usage = "\n"
-" test-tool bloom get_murmer3 <string>\n"
+" test-tool bloom get_murmur3 <string>\n"
" test-tool bloom generate_filter <string> [<string>...]\n"
" test-tool get_filter_for_commit <commit-hex>\n";
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
index 2e73658a5c..526304ff95 100755
--- a/t/t0091-bugreport.sh
+++ b/t/t0091-bugreport.sh
@@ -57,5 +57,20 @@ test_expect_success 'can create leading directories outside of a git dir' '
nongit git bugreport -o foo/bar/baz
'
+test_expect_success 'indicates populated hooks' '
+ test_when_finished rm git-bugreport-hooks.txt &&
+ test_when_finished rm -fr .git/hooks &&
+ rm -fr .git/hooks &&
+ mkdir .git/hooks &&
+ for hook in applypatch-msg prepare-commit-msg.sample
+ do
+ write_script ".git/hooks/$hook" <<-EOF || return 1
+ echo "hook $hook exists"
+ EOF
+ done &&
+ git bugreport -s hooks &&
+ grep applypatch-msg git-bugreport-hooks.txt &&
+ ! grep prepare-commit-msg git-bugreport-hooks.txt
+'
test_done
diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh
index 809ec7b0b8..232ba2c485 100755
--- a/t/t0095-bloom.sh
+++ b/t/t0095-bloom.sh
@@ -89,8 +89,8 @@ test_expect_success 'get bloom filter for commit with 10 changes' '
git add smallDir &&
git commit -m "commit with 10 changes" &&
cat >expect <<-\EOF &&
- Filter_Length:25
- Filter_Data:82|a0|65|47|0c|92|90|c0|a1|40|02|a0|e2|40|e0|04|0a|9a|66|cf|80|19|85|42|23|
+ Filter_Length:14
+ Filter_Data:02|b3|c4|a0|34|e7|fe|eb|cb|47|fe|a0|e8|72|
EOF
test-tool bloom get_filter_for_commit "$(git rev-parse HEAD)" >actual &&
test_cmp expect actual
@@ -100,7 +100,7 @@ test_expect_success EXPENSIVE 'get bloom filter for commit with 513 changes' '
rm actual &&
rm expect &&
mkdir bigDir &&
- for i in $(test_seq 0 512)
+ for i in $(test_seq 0 511)
do
echo $i >bigDir/$i
done &&
diff --git a/t/t0500-progress-display.sh b/t/t0500-progress-display.sh
index d2d088d9a0..1ed1df351c 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -283,4 +283,30 @@ test_expect_success 'cover up after throughput shortens a lot' '
test_i18ncmp expect out
'
+test_expect_success 'progress generates traces' '
+ cat >in <<-\EOF &&
+ throughput 102400 1000
+ update
+ progress 10
+ throughput 204800 2000
+ update
+ progress 20
+ throughput 307200 3000
+ update
+ progress 30
+ throughput 409600 4000
+ update
+ progress 40
+ EOF
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" test-tool progress --total=40 \
+ "Working hard" <in 2>stderr &&
+
+ # t0212/parse_events.perl intentionally omits regions and data.
+ grep -e "region_enter" -e "\"category\":\"progress\"" trace.event &&
+ grep -e "region_leave" -e "\"category\":\"progress\"" trace.event &&
+ grep "\"key\":\"total_objects\",\"value\":\"40\"" trace.event &&
+ grep "\"key\":\"total_bytes\",\"value\":\"409600\"" trace.event
+'
+
test_done
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 449ebc5657..91a6e34f38 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -257,6 +257,22 @@ test_expect_success 'tree object with duplicate entries' '
test_i18ngrep "error in tree .*contains duplicate file entries" out
'
+test_expect_success 'tree object with dublicate names' '
+ test_when_finished "remove_object \$blob" &&
+ test_when_finished "remove_object \$tree" &&
+ test_when_finished "remove_object \$badtree" &&
+ blob=$(echo blob | git hash-object -w --stdin) &&
+ printf "100644 blob %s\t%s\n" $blob x.2 >tree &&
+ tree=$(git mktree <tree) &&
+ printf "100644 blob %s\t%s\n" $blob x.1 >badtree &&
+ printf "100644 blob %s\t%s\n" $blob x >>badtree &&
+ printf "040000 tree %s\t%s\n" $tree x >>badtree &&
+ badtree=$(git mktree <badtree) &&
+ test_must_fail git fsck 2>out &&
+ test_i18ngrep "$badtree" out &&
+ test_i18ngrep "error in tree .*contains duplicate file entries" out
+'
+
test_expect_success 'unparseable tree object' '
test_oid_cache <<-\EOF &&
junk sha1:twenty-bytes-of-junk
diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh
index 553a3f601b..fd2f7abf1c 100755
--- a/t/t1509-root-work-tree.sh
+++ b/t/t1509-root-work-tree.sh
@@ -221,7 +221,7 @@ test_expect_success 'setup' '
rm -rf /.git &&
echo "Initialized empty Git repository in /.git/" > expected &&
git init > result &&
- test_cmp expected result
+ test_i18ncmp expected result
'
test_vars 'auto gitdir, root' ".git" "/" ""
@@ -246,7 +246,7 @@ test_expect_success 'setup' '
cd / &&
echo "Initialized empty Git repository in /" > expected &&
git init --bare > result &&
- test_cmp expected result
+ test_i18ncmp expected result
'
test_vars 'auto gitdir, root' "." "" ""
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index 093de9005b..7bab6000dc 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -424,4 +424,20 @@ test_expect_success 'abort last squash' '
! grep first actual
'
+test_expect_success 'fixup a fixup' '
+ echo 0to-fixup >file0 &&
+ test_tick &&
+ git commit -m "to-fixup" file0 &&
+ test_tick &&
+ git commit --squash HEAD -m X --allow-empty &&
+ test_tick &&
+ git commit --squash HEAD^ -m Y --allow-empty &&
+ test_tick &&
+ git commit -m "squash! $(git rev-parse HEAD^)" -m Z --allow-empty &&
+ test_tick &&
+ git commit -m "squash! $(git rev-parse HEAD^^)" -m W --allow-empty &&
+ git rebase -ki --autosquash HEAD~5 &&
+ test XZWY = $(git show | tr -cd W-Z)
+'
+
test_done
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 030a7222b2..7214cab36c 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -538,6 +538,33 @@ test_expect_success 'repack with minimum size does not alter existing packs' '
)
'
+test_expect_success 'repack respects repack.packKeptObjects=false' '
+ test_when_finished rm -f dup/.git/objects/pack/*keep &&
+ (
+ cd dup &&
+ ls .git/objects/pack/*idx >idx-list &&
+ test_line_count = 5 idx-list &&
+ ls .git/objects/pack/*.pack | sed "s/\.pack/.keep/" >keep-list &&
+ test_line_count = 5 keep-list &&
+ for keep in $(cat keep-list)
+ do
+ touch $keep || return 1
+ done &&
+ git multi-pack-index repack --batch-size=0 &&
+ ls .git/objects/pack/*idx >idx-list &&
+ test_line_count = 5 idx-list &&
+ test-tool read-midx .git/objects | grep idx >midx-list &&
+ test_line_count = 5 midx-list &&
+ THIRD_SMALLEST_SIZE=$(test-tool path-utils file-size .git/objects/pack/*pack | sort -n | sed -n 3p) &&
+ BATCH_SIZE=$((THIRD_SMALLEST_SIZE + 1)) &&
+ git multi-pack-index repack --batch-size=$BATCH_SIZE &&
+ ls .git/objects/pack/*idx >idx-list &&
+ test_line_count = 5 idx-list &&
+ test-tool read-midx .git/objects | grep idx >midx-list &&
+ test_line_count = 5 midx-list
+ )
+'
+
test_expect_success 'repack creates a new pack' '
(
cd dup &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 52dd1a688c..8c54e34ef1 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -386,7 +386,7 @@ test_expect_success 'clone shallow with packed refs' '
'
test_expect_success 'in_vain not triggered before first ACK' '
- rm -rf myserver myclient trace &&
+ rm -rf myserver myclient &&
git init myserver &&
test_commit -C myserver foo &&
git clone "file://$(pwd)/myserver" myclient &&
@@ -399,12 +399,12 @@ test_expect_success 'in_vain not triggered before first ACK' '
# The new commit that the client wants to fetch.
test_commit -C myserver bar &&
- GIT_TRACE_PACKET="$(pwd)/trace" git -C myclient fetch --progress origin &&
- test_i18ngrep "Total 3 " trace
+ git -C myclient fetch --progress origin 2>log &&
+ test_i18ngrep "remote: Total 3 " log
'
test_expect_success 'in_vain resetted upon ACK' '
- rm -rf myserver myclient trace &&
+ rm -rf myserver myclient &&
git init myserver &&
# Linked list of commits on master. The first is common; the rest are
@@ -429,8 +429,8 @@ test_expect_success 'in_vain resetted upon ACK' '
# first. The 256th commit is common between the client and the server,
# and should reset in_vain. This allows negotiation to continue until
# the client reports that first_anotherbranch_commit is common.
- GIT_TRACE_PACKET="$(pwd)/trace" git -C myclient fetch --progress origin master &&
- test_i18ngrep "Total 3 " trace
+ git -C myclient fetch --progress origin master 2>log &&
+ test_i18ngrep "Total 3 " log
'
test_expect_success 'fetch in shallow repo unreachable shallow objects' '
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1313142564..ac31faefa1 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -792,6 +792,13 @@ test_expect_success 'bisect replay with old and new' '
git bisect reset
'
+test_expect_success 'bisect replay with CRLF log' '
+ append_cr <log_to_replay.txt >log_to_replay_crlf.txt &&
+ git bisect replay log_to_replay_crlf.txt >bisect_result_crlf &&
+ grep "$HASH2 is the first new commit" bisect_result_crlf &&
+ git bisect reset
+'
+
test_expect_success 'bisect cannot mix old/new and good/bad' '
git bisect start &&
git bisect bad $HASH4 &&
diff --git a/t/t9834-git-p4-file-dir-bug.sh b/t/t9834-git-p4-file-dir-bug.sh
new file mode 100755
index 0000000000..031e1f8668
--- /dev/null
+++ b/t/t9834-git-p4-file-dir-bug.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+test_description='git p4 directory/file bug handling
+
+This test creates files and directories with the same name in perforce and
+checks that git-p4 recovers from the error at the same time as the perforce
+repository.'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+ start_p4d &&
+ test_might_fail p4 configure set submit.collision.check=0
+'
+
+test_expect_success 'init depot' '
+ (
+ cd "$cli" &&
+
+ touch add_file_add_dir_del_file add_file_add_dir_del_dir &&
+ p4 add add_file_add_dir_del_file add_file_add_dir_del_dir &&
+ mkdir add_dir_add_file_del_file add_dir_add_file_del_dir &&
+ touch add_dir_add_file_del_file/file add_dir_add_file_del_dir/file &&
+ p4 add add_dir_add_file_del_file/file add_dir_add_file_del_dir/file &&
+ p4 submit -d "add initial" &&
+
+ rm -f add_file_add_dir_del_file add_file_add_dir_del_dir &&
+ mkdir add_file_add_dir_del_file add_file_add_dir_del_dir &&
+ touch add_file_add_dir_del_file/file add_file_add_dir_del_dir/file &&
+ p4 add add_file_add_dir_del_file/file add_file_add_dir_del_dir/file &&
+ rm -rf add_dir_add_file_del_file add_dir_add_file_del_dir &&
+ touch add_dir_add_file_del_file add_dir_add_file_del_dir &&
+ p4 add add_dir_add_file_del_file add_dir_add_file_del_dir &&
+ p4 submit -d "add conflicting" &&
+
+ p4 delete -k add_file_add_dir_del_file &&
+ p4 delete -k add_file_add_dir_del_dir/file &&
+ p4 delete -k add_dir_add_file_del_file &&
+ p4 delete -k add_dir_add_file_del_dir/file &&
+ p4 submit -d "delete conflicting" &&
+
+ p4 delete -k "add_file_add_dir_del_file/file" &&
+ p4 delete -k "add_file_add_dir_del_dir" &&
+ p4 delete -k "add_dir_add_file_del_file/file" &&
+ p4 delete -k "add_dir_add_file_del_dir" &&
+ p4 submit -d "delete remaining"
+ )
+'
+
+test_expect_success 'clone with git-p4' '
+ git p4 clone --dest="$git" //depot/@1,3
+'
+
+test_expect_success 'check contents' '
+ test_path_is_dir "$git/add_file_add_dir_del_file" &&
+ test_path_is_file "$git/add_file_add_dir_del_dir" &&
+ test_path_is_dir "$git/add_dir_add_file_del_file" &&
+ test_path_is_file "$git/add_dir_add_file_del_dir"
+'
+
+test_expect_success 'rebase and check empty' '
+ git -C "$git" p4 rebase &&
+
+ test_path_is_missing "$git/add_file_add_dir_del_file" &&
+ test_path_is_missing "$git/add_file_add_dir_del_dir" &&
+ test_path_is_missing "$git/add_dir_add_file_del_file" &&
+ test_path_is_missing "$git/add_dir_add_file_del_dir"
+'
+
+test_done